GCC Code Coverage Report


Directory: ./
File: storage/innobase/fil/fil0fil.cc
Date: 2022-11-26 14:12:44
Exec Total Coverage
Lines: 3627 4480 81.0%
Branches: 3107 6533 47.6%

Line Branch Exec Source
1 /*****************************************************************************
2
3 Copyright (c) 1995, 2022, Oracle and/or its affiliates.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25 *****************************************************************************/
26
27 /** @file fil/fil0fil.cc
28 The tablespace memory cache */
29
30 #include "my_config.h"
31
32 #include "detail/fil/open_files_limit.h"
33
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <scope_guard.h>
38
39 #include "mysqld.h" // server_uuid
40
41 #include "arch0page.h"
42 #include "btr0btr.h"
43 #include "buf0buf.h"
44 #include "buf0flu.h"
45 #include "dict0boot.h"
46 #include "dict0dd.h"
47 #include "dict0dict.h"
48 #include "fsp0file.h"
49 #include "fsp0fsp.h"
50 #include "fsp0space.h"
51 #include "fsp0sysspace.h"
52 #include "ha_prototypes.h"
53 #include "hash0hash.h"
54 #include "log0buf.h"
55 #include "log0chkp.h"
56 #include "log0recv.h"
57 #include "log0write.h"
58 #include "mach0data.h"
59 #include "mem0mem.h"
60 #include "mtr0log.h"
61 #include "my_dbug.h"
62 #include "ut0new.h"
63
64 #include "clone0api.h"
65 #include "os0file.h"
66 #include "page0zip.h"
67 #include "sql/mysqld.h" // lower_case_file_system
68 #include "srv0srv.h"
69 #include "srv0start.h"
70
71 #include "fil0crypt.h"
72
73 #ifndef UNIV_HOTBACKUP
74 #include "buf0lru.h"
75 #include "ibuf0ibuf.h"
76 #include "os0event.h"
77 #include "row0mysql.h"
78 #include "sql_backup_lock.h"
79 #include "sql_class.h"
80 #include "sync0sync.h"
81 #include "trx0purge.h"
82 #else /* !UNIV_HOTBACKUP */
83 #include <cstring>
84 #include "srv0srv.h"
85 #endif /* !UNIV_HOTBACKUP */
86 #include "system_key.h"
87
88 #include "os0thread-create.h"
89
90 #include "current_thd.h"
91 #include "ha_prototypes.h"
92
93 #include <array>
94 #include <fstream>
95 #include <functional>
96 #include <list>
97 #include <mutex>
98 #include <thread>
99 #include <tuple>
100 #include <unordered_map>
101
102 using Dirs = std::vector<std::string>;
103 using Space_id_set = std::set<space_id_t>;
104
105 constexpr char Fil_path::DB_SEPARATOR;
106 constexpr char Fil_path::OS_SEPARATOR;
107 constexpr const char *Fil_path::SEPARATOR;
108 constexpr const char *Fil_path::DOT_SLASH;
109 constexpr const char *Fil_path::DOT_DOT_SLASH;
110 constexpr const char *Fil_path::SLASH_DOT_DOT_SLASH;
111
112 dberr_t dict_stats_rename_table(const char *old_name, const char *new_name,
113 char *errstr, size_t errstr_sz);
114
115 /** Used for collecting the data in boot_tablespaces() */
116 namespace dd_fil {
117
118 enum {
119 /** DD Object ID */
120 OBJECT_ID,
121
122 /** InnoDB tablspace ID */
123 SPACE_ID,
124
125 /** DD/InnoDB tablespace name */
126 SPACE_NAME,
127
128 /** Path in DD tablespace */
129 OLD_PATH,
130
131 /** Path where it was found during the scan. */
132 NEW_PATH
133 };
134
135 using Moved = std::tuple<dd::Object_id, space_id_t, std::string, std::string,
136 std::string>;
137
138 using Tablespaces = std::vector<Moved>;
139 } // namespace dd_fil
140
141 23525 size_t fil_get_scan_threads(size_t num_files) {
142 /* Number of additional threads required to scan all the files.
143 n_threads == 0 means that the main thread itself will do all the
144 work instead of spawning any additional threads. */
145 23525 size_t n_threads = num_files / FIL_SCAN_MAX_TABLESPACES_PER_THREAD;
146
147 /* Return if no additional threads are needed. */
148
1/2
✓ Branch 0 taken 23525 times.
✗ Branch 1 not taken.
23525 if (n_threads == 0) {
149 23525 return 0;
150 }
151
152 /* Number of concurrent threads supported by the host machine. */
153 size_t max_threads =
154 FIL_SCAN_THREADS_PER_CORE * std::thread::hardware_concurrency();
155
156 /* If the number of concurrent threads supported by the host
157 machine could not be calculated, assume the supported threads
158 to be FIL_SCAN_MAX_THREADS. */
159 max_threads = max_threads == 0 ? FIL_SCAN_MAX_THREADS : max_threads;
160
161 /* Restrict the number of threads to the lower of number of threads
162 supported by the host machine or FIL_SCAN_MAX_THREADS. */
163 if (n_threads > max_threads) {
164 n_threads = max_threads;
165 }
166
167 if (n_threads > FIL_SCAN_MAX_THREADS) {
168 n_threads = FIL_SCAN_MAX_THREADS;
169 }
170
171 return n_threads;
172 }
173
174 /* uint16_t is the index into Tablespace_dirs::m_dirs */
175 using Scanned_files = std::vector<std::pair<uint16_t, std::string>>;
176
177 #ifdef UNIV_PFS_IO
178 mysql_pfs_key_t innodb_tablespace_open_file_key;
179 #endif /* UNIV_PFS_IO */
180
181 /** System tablespace. */
182 fil_space_t *fil_space_t::s_sys_space;
183
184 #ifdef UNIV_HOTBACKUP
185 /** Directories in which remote general tablespaces have been found in the
186 target directory during apply log operation */
187 Dir_set rem_gen_ts_dirs;
188
189 /** true in case the apply-log operation is being performed
190 in the data directory */
191 bool replay_in_datadir = false;
192
193 /* Re-define mutex macros to use the Mutex class defined by the MEB
194 source. MEB calls the routines in "fil0fil.cc" in parallel and,
195 therefore, the mutex protecting the critical sections of the tablespace
196 memory cache must be included also in the MEB compilation of this
197 module. */
198 #undef mutex_create
199 #undef mutex_free
200 #undef mutex_enter
201 #undef mutex_exit
202 #undef mutex_own
203 #undef mutex_validate
204
205 #define mutex_create(I, M) new (M) meb::Mutex()
206 #define mutex_free(M) delete (M)
207 #define mutex_enter(M) (M)->lock()
208 #define mutex_exit(M) (M)->unlock()
209 #define mutex_own(M) 1
210 #define mutex_validate(M) 1
211
212 /** Process a MLOG_FILE_CREATE redo record.
213 @param[in] page_id Page id of the redo log record
214 @param[in] flags Tablespace flags
215 @param[in] name Tablespace filename */
216 static void meb_tablespace_redo_create(const page_id_t &page_id, uint32_t flags,
217 const char *name);
218
219 /** Process a MLOG_FILE_RENAME redo record.
220 @param[in] page_id Page id of the redo log record
221 @param[in] from_name Tablespace from filename
222 @param[in] to_name Tablespace to filename */
223 static void meb_tablespace_redo_rename(const page_id_t &page_id,
224 const char *from_name,
225 const char *to_name);
226
227 /** Process a MLOG_FILE_DELETE redo record.
228 @param[in] page_id Page id of the redo log record
229 @param[in] name Tablespace filename */
230 static void meb_tablespace_redo_delete(const page_id_t &page_id,
231 const char *name);
232
233 #endif /* UNIV_HOTBACKUP */
234
235 /*
236 IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
237 =============================================
238
239 The tablespace cache is responsible for providing fast read/write access to
240 tablespaces. File creation and deletion is done in other modules which know
241 more of the logic of the operation, however.
242
243 Only the system tablespace consists of a list of files. The size of these
244 files does not have to be divisible by the database block size, because
245 we may just leave the last incomplete block unused. When a new file is
246 appended to the tablespace, the maximum size of the file is also specified.
247 At the moment, we think that it is best to extend the file to its maximum
248 size already at the creation of the file, because then we can avoid dynamically
249 extending the file when more space is needed for the tablespace.
250
251 Non system tablespaces contain only a single file.
252
253 A block's position in the tablespace is specified with a 32-bit unsigned
254 integer. The files in the list are thought to be catenated, and the block
255 corresponding to an address n is the nth block in the catenated file (where
256 the first block is named the 0th block, and the incomplete block fragments
257 at the end of files are not taken into account). A tablespace can be extended
258 by appending a new file at the end of the list.
259
260 Our tablespace concept is similar to the one of Oracle.
261
262 To have fast access to a tablespace file, we put the data structures to
263 a hash table. Each tablespace file is given an unique 32-bit identifier,
264 its tablespace ID.
265
266 Some operating systems do not support many open files at the same time, or have
267 a limit set for user or process. Therefore, we put the open files that can be
268 easily closed in an LRU-list. If we need to open another file, we may close the
269 file at the end of the LRU-list. When an I/O-operation is pending on a file, the
270 file cannot be closed - we take the file nodes with pending I/O-operations out
271 of the LRU-list and keep a count of pending operations for each such file node.
272 When an operation completes, we decrement the count and return the file to the
273 LRU-list if the count drops to zero.
274
275 The data structure (Fil_shard) that keeps track of the tablespace ID to
276 fil_space_t* mapping are hashed on the tablespace ID. The tablespace name to
277 fil_space_t* mapping is stored in the same shard. A shard tracks the flushing
278 and open state of a file. When we run out open file handles, we use a ticketing
279 system to serialize the file open, see Fil_shard::reserve_open_slot() and
280 Fil_shard::release_open_slot().
281
282 When updating the global/shared data in Fil_system acquire the mutexes of
283 all shards in ascending order. The shard mutex covers the fil_space_t data
284 members as noted in the fil_space_t and fil_node_t definition. */
285
286 /** Reference to the server data directory. */
287 Fil_path MySQL_datadir_path;
288
289 /** Reference to the server undo directory. */
290 Fil_path MySQL_undo_path;
291
292 /** The undo path is different from any other known directory. */
293 bool MySQL_undo_path_is_unique;
294
295 /** Common InnoDB file extentions */
296 const char *dot_ext[] = {"", ".ibd", ".cfg", ".cfp",
297 ".ibt", ".ibu", ".dblwr", ".bdblwr"};
298
299 /** Number of pending tablespace flushes */
300 ulint fil_n_pending_tablespace_flushes = 0;
301
302 /** Number of files currently open */
303 std::atomic_size_t fil_n_files_open{0};
304
305 /** At this age or older a space/page will be rotated */
306 extern uint srv_fil_crypt_rotate_key_age;
307 extern ib_mutex_t fil_crypt_threads_mutex;
308 extern ib_mutex_t fil_crypt_list_mutex;
309
310 extern uint srv_n_fil_crypt_threads_requested;
311
312 enum fil_load_status {
313 /** The tablespace file(s) were found and valid. */
314 FIL_LOAD_OK,
315
316 /** The name no longer matches space_id */
317 FIL_LOAD_ID_CHANGED,
318
319 /** The file(s) were not found */
320 FIL_LOAD_NOT_FOUND,
321
322 /** The file(s) were not valid */
323 FIL_LOAD_INVALID,
324
325 /** The tablespace file ID in the first page doesn't match
326 expected value. */
327 FIL_LOAD_MISMATCH,
328
329 /** Doublewrite buffer corruption */
330 FIL_LOAD_DBWLR_CORRUPTION
331 };
332
333 /** File operations for tablespace */
334 enum fil_operation_t {
335
336 /** delete a single-table tablespace */
337 FIL_OPERATION_DELETE,
338
339 /** close a single-table tablespace */
340 FIL_OPERATION_CLOSE
341 };
342
343 /** The null file address */
344 fil_addr_t fil_addr_null = {FIL_NULL, 0};
345
346 /** Maximum number of pages to read to determine the space ID. */
347 static const size_t MAX_PAGES_TO_READ = 1;
348
349 #ifndef UNIV_HOTBACKUP
350 /** Maximum number of shards supported. */
351 static const size_t MAX_SHARDS = 68;
352
353 /** Number of undo shards to reserve. */
354 static const size_t UNDO_SHARDS = 4;
355
356 /** The UNDO logs have their own shards (4). */
357 static const size_t UNDO_SHARDS_START = MAX_SHARDS - UNDO_SHARDS;
358 #else /* !UNIV_HOTBACKUP */
359
360 /** Maximum number of shards supported. */
361 static const size_t MAX_SHARDS = 1;
362
363 /** The UNDO logs have their own shards (4). */
364 static const size_t UNDO_SHARDS_START = 0;
365 #endif /* !UNIV_HOTBACKUP */
366
367 /** We want to store the line number from where it was called. */
368 #define mutex_acquire() acquire(__LINE__)
369
370 /** Hash a NUL terminated 'string' */
371 struct Char_Ptr_Hash {
372 /** Hashing function
373 @param[in] ptr NUL terminated string to hash
374 @return the hash */
375 12710687 size_t operator()(const char *ptr) const {
376 12710687 return static_cast<size_t>(ut::hash_string(ptr));
377 }
378 };
379
380 /** Compare two 'strings' */
381 struct Char_Ptr_Compare {
382 /** Compare two NUL terminated strings
383 @param[in] lhs Left hand side
384 @param[in] rhs Right hand side
385 @return true if the contents match */
386 996631 bool operator()(const char *lhs, const char *rhs) const {
387 996631 return (strcmp(lhs, rhs) == 0);
388 }
389 };
390
391 /** Tablespace files discovered during startup. */
392 class Tablespace_files {
393 public:
394 using Names = std::vector<std::string, ut::allocator<std::string>>;
395 using Paths = std::unordered_map<space_id_t, Names>;
396 using Undo_num2id = std::unordered_map<space_id_t, space_id_t>;
397
398 /** Default constructor
399 @param[in] dir Directory that the files are under */
400 explicit Tablespace_files(const std::string &dir);
401
402 /** Add a space ID to filename mapping.
403 @param[in] space_id Tablespace ID
404 @param[in] name File name.
405 @return number of files that map to the space ID */
406 [[nodiscard]] size_t add(space_id_t space_id, const std::string &name);
407
408 /** Get the file names that map to a space ID
409 @param[in] space_id Tablespace ID
410 @return the filenames that map to space id */
411 16832944 [[nodiscard]] Names *find_by_id(space_id_t space_id) {
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16832944 times.
16832944 ut_ad(space_id != TRX_SYS_SPACE);
413
414
2/2
✓ Branch 0 taken 7240862 times.
✓ Branch 1 taken 9592082 times.
16832944 if (undo::is_reserved(space_id)) {
415
1/2
✓ Branch 0 taken 7240862 times.
✗ Branch 1 not taken.
7240862 auto it = m_undo_paths.find(space_id);
416
417
2/2
✓ Branch 0 taken 7207127 times.
✓ Branch 1 taken 33735 times.
7240862 if (it != m_undo_paths.end()) {
418 7207127 return &it->second;
419 }
420
421 } else {
422
1/2
✓ Branch 0 taken 9592082 times.
✗ Branch 1 not taken.
9592082 auto it = m_ibd_paths.find(space_id);
423
424
2/2
✓ Branch 0 taken 8683445 times.
✓ Branch 1 taken 908637 times.
9592082 if (it != m_ibd_paths.end()) {
425 8683445 return &it->second;
426 }
427 }
428
429 942372 return nullptr;
430 }
431
432 /** Get the file name that maps to an undo space number
433 @param[in] space_num undo tablespace number
434 @param[out] space_id undo tablespace ID
435 @return the file name that maps to the space number */
436 1496390 [[nodiscard]] Names *find_by_num(space_id_t space_num, space_id_t &space_id) {
437
3/6
✓ Branch 0 taken 1496390 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1496390 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1496390 times.
1496390 ut_ad(space_num > 0 && space_num <= FSP_MAX_UNDO_TABLESPACES);
438
1/2
✓ Branch 0 taken 1496390 times.
✗ Branch 1 not taken.
1496390 auto it_nums = m_undo_nums.find(space_num);
439
2/2
✓ Branch 0 taken 1473016 times.
✓ Branch 1 taken 23374 times.
1496390 if (it_nums == m_undo_nums.end()) {
440 1473016 return (nullptr);
441 }
442 23374 space_id = it_nums->second;
443
444
1/2
✓ Branch 0 taken 23374 times.
✗ Branch 1 not taken.
23374 auto it = m_undo_paths.find(space_id);
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23374 times.
23374 ut_ad(it != m_undo_paths.end());
446
447 23374 return (&it->second);
448 }
449
450 /** Remove the entry for the space ID.
451 @param[in] space_id Tablespace ID mapping to remove
452 @return true if erase successful */
453 24 [[nodiscard]] bool erase_path(space_id_t space_id) {
454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 ut_ad(space_id != TRX_SYS_SPACE);
455
456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (undo::is_reserved(space_id)) {
457 auto n_erased = m_undo_nums.erase(undo::id2num(space_id));
458 ut_ad(n_erased == 1);
459
460 n_erased = m_undo_paths.erase(space_id);
461
462 return (n_erased == 1);
463 } else {
464 24 auto n_erased = m_ibd_paths.erase(space_id);
465
466 24 return (n_erased == 1);
467 }
468 }
469
470 /** Clear all the tablespace data. */
471 11960 void clear() {
472 11960 m_ibd_paths.clear();
473 11960 m_undo_paths.clear();
474 11960 m_undo_nums.clear();
475 11960 }
476
477 /** @return m_dir */
478 59641 const Fil_path &root() const { return m_dir; }
479
480 /** @return the directory path specified by the user. */
481 16048588 const std::string &path() const { return m_dir.path(); }
482
483 private:
484 /* Note: The file names in m_ibd_paths and m_undo_paths are relative
485 to m_real_path. */
486
487 /** Mapping from tablespace ID to data filenames */
488 Paths m_ibd_paths;
489
490 /** Mapping from tablespace ID to Undo files */
491 Paths m_undo_paths;
492
493 /** Mapping from undo space number to space ID */
494 Undo_num2id m_undo_nums;
495
496 /** Top level directory where the above files were found. */
497 Fil_path m_dir;
498 };
499
500 /** Directories scanned during startup and the files discovered. */
501 class Tablespace_dirs {
502 public:
503 using Result = std::pair<std::string, Tablespace_files::Names *>;
504
505 /** Constructor */
506 12330 Tablespace_dirs() : m_dirs(), m_checked() {}
507
508 /** Normalize and save a directory to scan for IBD and IBU datafiles
509 before recovery.
510 @param[in] directory directory to scan for ibd and ibu files
511 @param[in] is_undo_dir true for an undo directory */
512 void set_scan_dir(const std::string &directory, bool is_undo_dir = false);
513
514 /** Normalize and save a list of directories to scan for IBD and IBU
515 datafiles before recovery.
516 @param[in] directories Directories to scan for ibd and ibu files */
517 void set_scan_dirs(const std::string &directories);
518
519 /** Discover tablespaces by reading the header from .ibd files.
520 @return DB_SUCCESS if all goes well */
521 [[nodiscard]] dberr_t scan();
522
523 /** Clear all the tablespace file data but leave the list of
524 scanned directories in place. */
525 11787 void clear() {
526
2/2
✓ Branch 0 taken 11960 times.
✓ Branch 1 taken 11787 times.
23747 for (auto &dir : m_dirs) {
527 11960 dir.clear();
528 }
529
530 11787 m_checked = 0;
531 11787 }
532
533 /** Erase a space ID to filename mapping.
534 @param[in] space_id Tablespace ID to erase
535 @return true if successful */
536 24 [[nodiscard]] bool erase_path(space_id_t space_id) {
537
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 for (auto &dir : m_dirs) {
538
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 if (dir.erase_path(space_id)) {
539 24 return true;
540 }
541 }
542
543 return false;
544 }
545
546 /* Find the first matching space ID -> name mapping.
547 @param[in] space_id Tablespace ID
548 @return directory searched and pointer to names that map to the
549 tablespace ID */
550 16999690 [[nodiscard]] Result find_by_id(space_id_t space_id) {
551
2/2
✓ Branch 0 taken 16832943 times.
✓ Branch 1 taken 1109119 times.
17942062 for (auto &dir : m_dirs) {
552
1/2
✓ Branch 0 taken 16832943 times.
✗ Branch 1 not taken.
16832943 const auto names = dir.find_by_id(space_id);
553
554
2/2
✓ Branch 0 taken 15890571 times.
✓ Branch 1 taken 942372 times.
16832943 if (names != nullptr) {
555
1/2
✓ Branch 0 taken 15890571 times.
✗ Branch 1 not taken.
15890571 return (Result{dir.path(), names});
556 }
557 }
558
559
1/2
✓ Branch 0 taken 1109119 times.
✗ Branch 1 not taken.
1109119 return (Result{"", nullptr});
560 }
561
562 /* Find the matching space number ->space ID -> name mapping.
563 @param[in] space_num undo tablespace number
564 @param[out] space_id undo tablespace ID
565 @return directory searched and pointer to name that maps to the
566 tablespace number */
567 1477403 [[nodiscard]] Result find_by_num(space_id_t space_num, space_id_t &space_id) {
568
2/2
✓ Branch 0 taken 1496390 times.
✓ Branch 1 taken 1454029 times.
2950419 for (auto &dir : m_dirs) {
569
1/2
✓ Branch 0 taken 1496390 times.
✗ Branch 1 not taken.
1496390 const auto names = dir.find_by_num(space_num, space_id);
570
571
2/2
✓ Branch 0 taken 23374 times.
✓ Branch 1 taken 1473016 times.
1496390 if (names != nullptr) {
572
1/2
✓ Branch 0 taken 23374 times.
✗ Branch 1 not taken.
23374 return Result{dir.path(), names};
573 }
574 }
575
576
1/2
✓ Branch 0 taken 1454029 times.
✗ Branch 1 not taken.
1454029 return Result{"", nullptr};
577 }
578
579 /** Determine if this Fil_path contains the path provided.
580 @param[in] path file or directory path to compare.
581 @return true if this Fil_path contains path */
582 16549 [[nodiscard]] bool contains(const std::string &path) const {
583
1/2
✓ Branch 0 taken 16549 times.
✗ Branch 1 not taken.
16549 const Fil_path descendant{path};
584
585
2/2
✓ Branch 0 taken 17335 times.
✓ Branch 1 taken 113 times.
17448 for (const auto &dir : m_dirs) {
586
5/6
✓ Branch 0 taken 17335 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5359 times.
✓ Branch 3 taken 11976 times.
✓ Branch 4 taken 16436 times.
✓ Branch 5 taken 899 times.
22694 if (dir.root().is_same_as(descendant) ||
587
3/4
✓ Branch 0 taken 5359 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4460 times.
✓ Branch 3 taken 899 times.
5359 dir.root().is_ancestor(descendant)) {
588 16436 return true;
589 }
590 }
591 113 return false;
592 16549 }
593
594 /** Get the list of directories that InnoDB knows about.
595 @return the list of directories 'dir1;dir2;....;dirN' */
596 11994 std::string get_dirs() const {
597 11994 std::string dirs;
598
599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11994 times.
11994 ut_ad(!m_dirs.empty());
600
601
2/2
✓ Branch 0 taken 12167 times.
✓ Branch 1 taken 11994 times.
24161 for (const auto &dir : m_dirs) {
602
1/2
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
12167 dirs.append(dir.root());
603
1/2
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
12167 dirs.push_back(FIL_PATH_SEPARATOR);
604 }
605
606 11994 dirs.pop_back();
607
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11994 times.
11994 ut_ad(!dirs.empty());
609
610 11994 return dirs;
611 }
612
613 private:
614 /** Print the duplicate filenames for a tablespace ID to the log
615 @param[in] duplicates Duplicate tablespace IDs*/
616 void print_duplicates(const Space_id_set &duplicates);
617
618 /** first=dir path from the user, second=files found under first. */
619 using Scanned = std::vector<Tablespace_files>;
620
621 /** Report a warning that a path is being ignored and include the reason. */
622 void warn_ignore(std::string path_in, const char *reason);
623
624 /** Add a single path specification to this list of tablespace directories.
625 Convert it to an absolute path. Check if the path is valid. Ignore
626 unreadable, duplicate or invalid directories.
627 @param[in] str Path specification to tokenize
628 @param[in] is_undo_dir true for an undo directory */
629 void add_path(const std::string &str, bool is_undo_dir = false);
630
631 /** Add a delimited list of path specifications to this list of tablespace
632 directories. Convert relative paths to absolute paths. Check if the paths
633 are valid. Ignore unreadable, duplicate or invalid directories.
634 @param[in] str Path specification to tokenize
635 @param[in] delimiters Delimiters */
636 void add_paths(const std::string &str, const std::string &delimiters);
637
638 using Const_iter = Scanned_files::const_iterator;
639
640 /** Check for duplicate tablespace IDs.
641 @param[in] start Start of slice
642 @param[in] end End of slice
643 @param[in] thread_id Thread ID
644 @param[in,out] mutex Mutex protecting the global state
645 @param[in,out] unique To check for duplicates
646 @param[in,out] duplicates Duplicate space IDs found */
647 void duplicate_check(const Const_iter &start, const Const_iter &end,
648 size_t thread_id, std::mutex *mutex,
649 Space_id_set *unique, Space_id_set *duplicates);
650
651 private:
652 /** Directories scanned and the files discovered under them. */
653 Scanned m_dirs;
654
655 /** Number of files checked. */
656 std::atomic_size_t m_checked;
657 };
658
659 /** Determine if space flushing should be disabled, for example when user has
660 explicitly disabled fsync(). */
661 33393599 static inline bool fil_disable_space_flushing(const fil_space_t *space) {
662 #ifndef _WIN32
663
2/2
✓ Branch 0 taken 31086697 times.
✓ Branch 1 taken 2306902 times.
33393599 if (space->purpose == FIL_TYPE_TABLESPACE &&
664
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 31086594 times.
31086697 srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC) {
665 103 return true;
666 }
667 #endif /* !_WIN32 */
668
2/2
✓ Branch 0 taken 2303605 times.
✓ Branch 1 taken 31089891 times.
33393496 if (space->purpose == FIL_TYPE_TEMPORARY) {
669 2303605 return true;
670 }
671 31089891 return false;
672 }
673
674 class Fil_shard {
675 using File_list = UT_LIST_BASE_NODE_T(fil_node_t, LRU);
676 using Space_list = UT_LIST_BASE_NODE_T(fil_space_t, unflushed_spaces);
677 using Full_space_list = UT_LIST_BASE_NODE_T(fil_space_t, space_list);
678 using Rotation_list = UT_LIST_BASE_NODE_T(fil_space_t, rotation_list);
679 using Spaces = std::unordered_map<space_id_t, fil_space_t *>;
680
681 using Names = std::unordered_map<const char *, fil_space_t *, Char_Ptr_Hash,
682 Char_Ptr_Compare>;
683
684 public:
685 /** Constructor
686 @param[in] shard_id Shard ID */
687 explicit Fil_shard(size_t shard_id);
688
689 /** Destructor */
690 723452 ~Fil_shard() {
691 723452 mutex_destroy(&m_mutex);
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 723452 times.
723452 ut_a(UT_LIST_GET_LEN(m_LRU) == 0);
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 723452 times.
723452 ut_a(UT_LIST_GET_LEN(m_unflushed_spaces) == 0);
694 723452 }
695
696 /** @return the shard ID */
697 size_t id() const { return m_id; }
698
699 /** Acquire the mutex.
700 @param[in] line Line number from where it was called */
701 3010654227 void acquire(int line) const {
702 #ifndef UNIV_HOTBACKUP
703 3010654227 m_mutex.enter(srv_n_spin_wait_rounds, srv_spin_wait_delay, __FILE__, line);
704 #else
705 mutex_enter(&m_mutex);
706 #endif /* !UNIV_HOTBACKUP */
707 3010345844 }
708
709 /** Release the mutex. */
710 3010849185 void mutex_release() const { mutex_exit(&m_mutex); }
711
712 #ifdef UNIV_DEBUG
713 /** @return true if the mutex is owned. */
714 10966174185 bool mutex_owned() const { return mutex_own(&m_mutex); }
715 #endif /* UNIV_DEBUG */
716
717 /** Acquire a tablespace to prevent it from being dropped concurrently.
718 The thread must call Fil_shard::fil_space_release() when the operation
719 is done.
720 @param[in] space tablespace to acquire
721 @return true if not space->stop_new_ops */
722 bool space_acquire(fil_space_t *space);
723
724 /** Release a tablespace acquired with Fil_shard::space_acquire().
725 @param[in,out] space tablespace to release */
726 void space_release(fil_space_t *space);
727
728 /** Fetch the fil_space_t instance that maps to space_id. Does not look
729 through system reserved spaces.
730 @param[in] space_id Tablespace ID to lookup
731 @return tablespace instance or nullptr if not found. */
732 1396981818 [[nodiscard]] fil_space_t *get_space_by_id_from_map(
733 space_id_t space_id) const {
734
2/4
✓ Branch 0 taken 1396990933 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1396989993 times.
1396981818 ut_ad(mutex_owned());
735
736
1/2
✓ Branch 0 taken 1396991946 times.
✗ Branch 1 not taken.
1396989993 auto it = m_spaces.find(space_id);
737
738 /* The system tablespace must always be found */
739
4/8
✓ Branch 0 taken 1037478 times.
✓ Branch 1 taken 1395948283 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1037478 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1396984436 times.
1396991946 ut_ad(it != m_spaces.end() || space_id != 0 || srv_is_being_started);
740
741
2/2
✓ Branch 0 taken 1037478 times.
✓ Branch 1 taken 1395943098 times.
1396984436 if (it == m_spaces.end()) {
742 1037478 return nullptr;
743 }
744
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1395944831 times.
1395943098 ut_ad(it->second->magic_n == FIL_SPACE_MAGIC_N);
746
5/8
✓ Branch 0 taken 1395942649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1257988535 times.
✓ Branch 3 taken 137954114 times.
✓ Branch 4 taken 1257988779 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1395942164 times.
1395944831 ut_ad(fsp_is_system_temporary(space_id) || it->second->files.size() == 1);
747
748 1395942164 return it->second;
749 }
750
751 /** Fetch the fil_space_t instance that maps to space_id.
752 @param[in] space_id Tablespace ID to lookup
753 @return tablespace instance or nullptr if not found. */
754 fil_space_t *get_space_by_id(space_id_t space_id) const;
755
756 /** Fetch the fil_space_t instance that maps to the name.
757 @param[in] name Tablespace name to lookup
758 @return tablespace instance or nullptr if not found. */
759 11441413 [[nodiscard]] fil_space_t *get_space_by_name(const char *name) const {
760
2/4
✓ Branch 0 taken 11441413 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11441413 times.
11441413 ut_ad(mutex_owned());
761
762
1/2
✓ Branch 0 taken 11441413 times.
✗ Branch 1 not taken.
11441413 auto it = m_names.find(name);
763
764
2/2
✓ Branch 0 taken 10962112 times.
✓ Branch 1 taken 479301 times.
11441413 if (it == m_names.end()) {
765 10962112 return nullptr;
766 }
767
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 479301 times.
479301 ut_ad(it->second->magic_n == FIL_SPACE_MAGIC_N);
769
770 479301 return it->second;
771 }
772
773 /** Tries to close a file in the shard LRU list.
774 The caller must hold the Fil_shard::m_mutex.
775 @return true if success, false if should retry later */
776 [[nodiscard]] bool close_files_in_LRU();
777
778 /** Remove the file node from the LRU list.
779 @param[in,out] file File for the tablespace */
780 void remove_from_LRU(fil_node_t *file);
781
782 /** Add the file node to the LRU list if required.
783 @param[in,out] file File for the tablespace */
784 void add_to_lru_if_needed(fil_node_t *file);
785
786 /** Open all the system files.
787 @param[in] max_n_open Maximum number of open files allowed
788 @param[in,out] n_open Current number of open files */
789 void open_system_tablespaces(size_t max_n_open, size_t *n_open);
790
791 /** Close a tablespace file.
792 @param[in,out] file Tablespace file to close */
793 void close_file(fil_node_t *file);
794
795 /** Close a tablespace file based on tablespace ID.
796 @param[in] space_id Tablespace ID
797 @return false if space_id was not found. */
798 bool close_file(space_id_t space_id);
799
800 /** Prepare to free a file object from a tablespace
801 memory cache.
802 @param[in,out] file Tablespace file
803 @param[in] space tablespace */
804 void file_close_to_free(fil_node_t *file, fil_space_t *space);
805
806 /** Close all open files. */
807 void close_all_files();
808
809 #ifndef UNIV_HOTBACKUP
810 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
811 /** Check that each fil_space_t::m_n_ref_count in this shard matches the
812 number of pages counted in the buffer pool.
813 @param[in] buffer_pool_references Map of spaces instances to the count
814 of their pages in the buffer pool. */
815 void validate_space_reference_count(Space_References &buffer_pool_references);
816 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
817 #endif /* !UNIV_HOTBACKUP */
818
819 /** Determine if the tablespace needs encryption rotation.
820 @param[in] space tablespace to rotate
821 @return true if the tablespace needs to be rotated, false if not. */
822 bool needs_encryption_rotate(fil_space_t *space);
823
824 /** Rotate the tablespace keys by new master key.
825 @param[in,out] rotate_count A cumulative count of all tablespaces rotated
826 in the Fil_system.
827 @return the number of tablespaces that failed to rotate. */
828 [[nodiscard]] size_t encryption_rotate(size_t *rotate_count);
829
830 /** Detach a space object from the tablespace memory cache and
831 closes the tablespace files but does not delete them.
832 There must not be any pending I/O's or flushes on the files.
833 @param[in,out] space tablespace */
834 void space_detach(fil_space_t *space);
835
836 /** Remove the fil_space_t instance from the maps used to search for it.
837 @param[in] space_id Tablespace ID to remove from maps. */
838 197546 void space_remove_from_lookup_maps(space_id_t space_id) {
839
2/4
✓ Branch 0 taken 197546 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197546 times.
197546 ut_ad(mutex_owned());
840
841
1/2
✓ Branch 0 taken 197546 times.
✗ Branch 1 not taken.
197546 auto it = m_spaces.find(space_id);
842
843
1/2
✓ Branch 0 taken 197546 times.
✗ Branch 1 not taken.
197546 if (it != m_spaces.end()) {
844
1/2
✓ Branch 0 taken 197546 times.
✗ Branch 1 not taken.
197546 m_names.erase(it->second->name);
845
1/2
✓ Branch 0 taken 197546 times.
✗ Branch 1 not taken.
197546 m_spaces.erase(it);
846 }
847 197546 }
848
849 #ifndef UNIV_HOTBACKUP
850 /** Move the space to the deleted list and remove from the default
851 lookup set.
852 @param[in, out] space Space instance to delete. */
853 217 void space_prepare_for_delete(fil_space_t *space) noexcept {
854 217 mutex_acquire();
855
856 217 space->set_deleted();
857
858 /* Remove access to the fil_space_t instance. */
859 217 space_remove_from_lookup_maps(space->id);
860
861 217 m_deleted_spaces.push_back({space->id, space});
862
863 217 space_detach(space);
864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 ut_a(space->files.size() == 1);
865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 ut_a(space->files.front().n_pending_ios == 0);
866
867 217 mutex_release();
868 217 }
869
870 /** Purge entries from m_deleted_spaces that are no longer referenced by a
871 buffer pool page. This is no longer required to be done during checkpoint -
872 this is done here for historical reasons - it has to be done periodically
873 somewhere. */
874 90651881 void purge() {
875 /* Avoid cleaning up old undo files while this is on. */
876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90651881 times.
90651881 DBUG_EXECUTE_IF("ib_undo_trunc_checkpoint_off", return;);
877
878 90651881 mutex_acquire();
879
2/2
✓ Branch 0 taken 1151988 times.
✓ Branch 1 taken 90651881 times.
91803869 for (auto it = m_deleted_spaces.begin(); it != m_deleted_spaces.end();) {
880 1151988 auto space = it->second;
881
882
3/4
✓ Branch 0 taken 1151988 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184317 times.
✓ Branch 3 taken 967671 times.
1151988 if (space->has_no_references()) {
883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184317 times.
184317 ut_a(space->files.size() == 1);
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184317 times.
184317 ut_a(space->files.front().n_pending_ios == 0);
885
886
1/2
✓ Branch 0 taken 184317 times.
✗ Branch 1 not taken.
184317 space_free_low(space);
887
888
1/2
✓ Branch 0 taken 184317 times.
✗ Branch 1 not taken.
184317 it = m_deleted_spaces.erase(it);
889 } else {
890 967671 ++it;
891 }
892 }
893
894 90651881 mutex_release();
895 }
896
897 /** Count how many truncated undo space IDs are still tracked in
898 the buffer pool and the file_system cache.
899 @param[in] undo_num undo tablespace number.
900 @return number of undo tablespaces that are still in memory. */
901 4304468 size_t count_undo_deleted(space_id_t undo_num) noexcept {
902 4304468 size_t count = 0;
903
904 4304468 mutex_acquire();
905
906
2/2
✓ Branch 0 taken 90422 times.
✓ Branch 1 taken 4304468 times.
4394890 for (auto deleted : m_deleted_spaces) {
907
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 89297 times.
90422 if (undo::id2num(deleted.first) == undo_num) {
908 1125 count++;
909 }
910 }
911
912 4304468 mutex_release();
913
914 4304468 return count;
915 }
916
917 /** Check if a particular space_id for a page in the buffer pool has
918 been deleted recently. Its space_id will be found in m_deleted_spaces
919 until Fil:shard::checkpoint removes the fil_space_t from Fil_system.
920 @param[in] space_id Tablespace ID to check.
921 @return true if this space_id is in the list of recently deleted spaces. */
922 bool is_deleted(space_id_t space_id) {
923 bool found = false;
924
925 mutex_acquire();
926
927 for (auto deleted : m_deleted_spaces) {
928 if (deleted.first == space_id) {
929 found = true;
930 break;
931 }
932 }
933
934 mutex_release();
935
936 return found;
937 }
938
939 #endif /* !UNIV_HOTBACKUP */
940
941 /** Frees a space object from the tablespace memory cache.
942 Closes a tablespaces' files but does not delete them.
943 There must not be any pending I/O's or flushes on the files.
944 @param[in] space_id Tablespace ID
945 @return fil_space_t instance on success or nullptr */
946 [[nodiscard]] fil_space_t *space_free(space_id_t space_id);
947
948 /** Map the space ID and name to the tablespace instance.
949 @param[in] space Tablespace instance */
950 void space_add(fil_space_t *space, fil_encryption_t mode);
951
952 /** Prepare to free a file. Remove from the unflushed list
953 if there are no pending flushes.
954 @param[in,out] file File instance to free */
955 void prepare_to_free_file(fil_node_t *file);
956
957 /** If the tablespace is on the unflushed list and there
958 are no pending flushes then remove from the unflushed list.
959 @param[in,out] space Tablespace to remove*/
960 void remove_from_unflushed_list(fil_space_t *space);
961
962 /** Updates the data structures when an I/O operation
963 finishes. Updates the pending I/O's field in the file
964 appropriately.
965 @param[in] file Tablespace file
966 @param[in] type Marks the file as modified type == WRITE */
967 void complete_io(fil_node_t *file, const IORequest &type);
968
969 /** Prepares a file for I/O. Opens the file if it is closed. Updates the
970 pending I/O's field in the file and the system appropriately. Takes the file
971 off the LRU list if it is in the LRU list.
972 @param[in] file Tablespace file for IO
973 @return false if the file can't be opened, otherwise true */
974 [[nodiscard]] bool prepare_file_for_io(fil_node_t *file);
975
976 /** Remap the tablespace to the new name.
977 @param[in] space Tablespace instance, with old name.
978 @param[in] new_name New tablespace name */
979 void update_space_name_map(fil_space_t *space, const char *new_name);
980
981 /** Flush to disk the writes in file spaces possibly cached by the OS
982 (note: spaces of type FIL_TYPE_TEMPORARY are skipped) */
983 void flush_file_spaces();
984
985 /** Try to extend a tablespace if it is smaller than the specified size.
986 @param[in,out] space tablespace
987 @param[in] size desired size in pages
988 @return whether the tablespace is at least as big as requested */
989 [[nodiscard]] bool space_extend(fil_space_t *space, page_no_t size);
990
991 /** Flushes to disk possible writes cached by the OS. If the space does
992 not exist or is being dropped, does not do anything.
993 @param[in] space_id file space ID (id of tablespace of the database)
994 */
995 void space_flush(space_id_t space_id);
996
997 /** Open a file of a tablespace.
998 The caller must own the shard mutex.
999 @param[in,out] file Tablespace file
1000 @return false if the file can't be opened, otherwise true */
1001 [[nodiscard]] bool open_file(fil_node_t *file);
1002
1003 /** Checks if all the file nodes in a space are flushed. The caller must hold
1004 the fil_system mutex.
1005 @param[in] space Tablespace to check
1006 @return true if all are flushed */
1007 [[nodiscard]] bool space_is_flushed(const fil_space_t *space);
1008
1009 /** Open each file of a tablespace if not already open.
1010 @param[in] space_id tablespace identifier
1011 @retval true if all file nodes were opened
1012 @retval false on failure */
1013 [[nodiscard]] bool space_open(space_id_t space_id);
1014
1015 /** Opens the files associated with a tablespace and returns a
1016 pointer to the fil_space_t that is in the memory cache associated
1017 with a space id.
1018 @param[in] space_id Get the tablespace instance or this ID
1019 @return file_space_t pointer, nullptr if space not found */
1020 [[nodiscard]] fil_space_t *space_load(space_id_t space_id);
1021
1022 /** Wait for pending operations on a tablespace to stop.
1023 @param[in] space_id Tablespace ID
1024 @param[out] space tablespace instance in memory
1025 @param[out] path tablespace path
1026 @return DB_SUCCESS or DB_TABLESPACE_NOT_FOUND. */
1027 [[nodiscard]] dberr_t wait_for_pending_operations(space_id_t space_id,
1028 fil_space_t *&space,
1029 char **path) const;
1030
1031 /** Rename a single-table tablespace.
1032 The tablespace must exist in the memory cache.
1033 @param[in] space_id Tablespace ID
1034 @param[in] old_path Old file name
1035 @param[in] new_name New tablespace name in the schema/space
1036 @param[in] new_path_in New file name, or nullptr if it
1037 is located in the normal data directory
1038 @return InnoDB error code */
1039 [[nodiscard]] dberr_t space_rename(space_id_t space_id, const char *old_path,
1040 const char *new_name,
1041 const char *new_path_in);
1042
1043 /** Deletes an IBD or IBU tablespace.
1044 The tablespace must be cached in the memory cache. This will delete the
1045 datafile, fil_space_t & fil_node_t entries from the file_system_t cache.
1046 @param[in] space_id Tablespace ID
1047 @param[in] buf_remove Specify the action to take on the pages
1048 for this table in the buffer pool.
1049 @return DB_SUCCESS, DB_TABLESPCE_NOT_FOUND or DB_IO_ERROR */
1050 [[nodiscard]] dberr_t space_delete(space_id_t space_id,
1051 buf_remove_t buf_remove);
1052
1053 /** Truncate the tablespace to needed size.
1054 @param[in] space_id Tablespace ID to truncate
1055 @param[in] size_in_pages Truncate size.
1056 @return true if truncate was successful. */
1057 [[nodiscard]] bool space_truncate(space_id_t space_id,
1058 page_no_t size_in_pages);
1059
1060 /** Create a space memory object and put it to the fil_system hash table.
1061 The tablespace name is independent from the tablespace file-name.
1062 Error messages are issued to the server log.
1063 @param[in] name Tablespace name
1064 @param[in] space_id Tablespace identifier
1065 @param[in] flags Tablespace flags
1066 @param[in] purpose Tablespace purpose
1067 @return pointer to created tablespace, to be filled in with fil_node_create()
1068 @retval nullptr on failure (such as when the same tablespace exists) */
1069 [[nodiscard]] fil_space_t *space_create(
1070 const char *name, space_id_t space_id, uint32_t flags, fil_type_t purpose,
1071 fil_space_crypt_t *crypt_data,
1072 fil_encryption_t mode = FIL_ENCRYPTION_DEFAULT);
1073
1074 /** Adjust temporary auto-generated names created during
1075 file discovery with correct tablespace names from the DD.
1076 @param[in,out] space Tablespace
1077 @param[in] dd_space_name Tablespace name from the DD
1078 @return true if the tablespace is a general or undo tablespace. */
1079 bool adjust_space_name(fil_space_t *space, const char *dd_space_name);
1080
1081 /** Returns true if a matching tablespace exists in the InnoDB
1082 tablespace memory cache.
1083 @param[in] space_id Tablespace ID
1084 @param[in] name Tablespace name used in fil_space_create().
1085 @param[in] print_err Print detailed error information to the
1086 error log if a matching tablespace is
1087 not found from memory.
1088 @param[in] adjust_space Whether to adjust space id on mismatch
1089 @return true if a matching tablespace exists in the memory cache */
1090 [[nodiscard]] bool space_check_exists(space_id_t space_id, const char *name,
1091 bool print_err, bool adjust_space);
1092
1093 /** Read or write data. This operation could be asynchronous (aio).
1094 @param[in] type IO context
1095 @param[in] sync whether synchronous aio is desired
1096 @param[in] page_id page id
1097 @param[in] page_size page size
1098 @param[in] byte_offset remainder of offset in bytes; in AIO this must
1099 be divisible by the OS block size
1100 @param[in] len how many bytes to read or write; this
1101 must not cross a file boundary; in AIO this must be a block size multiple
1102 @param[in,out] buf buffer where to store read data or from
1103 where to write; in AIO this must be appropriately aligned
1104 @param[in] message message for AIO handler if !sync, else ignored
1105 @param[in] should_buffer whether to buffer an aio request. AIO read
1106 ahead uses this. If you plan to use this parameter, make sure you remember to
1107 call os_aio_dispatch_read_array_submit() when you're ready to commit all your
1108 requests.
1109 @return error code
1110 @retval DB_SUCCESS on success
1111 @retval DB_TABLESPACE_DELETED if the tablespace does not exist */
1112 [[nodiscard]] dberr_t do_io(const IORequest &type, bool sync,
1113 const page_id_t &page_id,
1114 const page_size_t &page_size, ulint byte_offset,
1115 ulint len, void *buf, void *message, trx_t *trx,
1116 bool should_buffer);
1117
1118 /** Iterate through all persistent tablespace files (FIL_TYPE_TABLESPACE)
1119 returning the nodes via callback function f.
1120 @param[in] f Callback
1121 @return any error returned by the callback function. */
1122 [[nodiscard]] dberr_t iterate(Fil_iterator::Function &f);
1123
1124 /** Open an ibd tablespace and add it to the InnoDB data structures.
1125 This is similar to fil_ibd_open() except that it is used while
1126 processing the redo and DDL log, so the data dictionary is not
1127 available and very little validation is done. The tablespace name
1128 is extracted from the dbname/tablename.ibd portion of the filename,
1129 which assumes that the file is a file-per-table tablespace. Any name
1130 will do for now. General tablespace names will be read from the
1131 dictionary after it has been recovered. The tablespace flags are read
1132 at this time from the first page of the file in validate_for_recovery().
1133 @param[in] space_id tablespace ID
1134 @param[in] path path/to/databasename/tablename.ibd
1135 @param[out] space the tablespace, or nullptr on error
1136 @return status of the operation */
1137 [[nodiscard]] fil_load_status ibd_open_for_recovery(space_id_t space_id,
1138 const std::string &path,
1139 fil_space_t *&space);
1140
1141 /** Attach a file to a tablespace
1142 @param[in] name file name of a file that is not open
1143 @param[in] size file size in entire database blocks
1144 @param[in,out] space tablespace from fil_space_create()
1145 @param[in] is_raw whether this is a raw device or partition
1146 @param[in] punch_hole true if supported for this file
1147 @param[in] atomic_write true if the file has atomic write enabled
1148 @param[in] max_pages maximum number of pages in file
1149 @return pointer to the file name
1150 @retval nullptr if error */
1151 [[nodiscard]] fil_node_t *create_node(const char *name, page_no_t size,
1152 fil_space_t *space, bool is_raw,
1153 bool punch_hole, bool atomic_write,
1154 page_no_t max_pages = PAGE_NO_MAX);
1155
1156 #ifdef UNIV_DEBUG
1157 /** Validate a shard. */
1158 void validate() const;
1159 #endif /* UNIV_DEBUG */
1160
1161 #ifdef UNIV_HOTBACKUP
1162 /** Extends all tablespaces to the size stored in the space header.
1163 During the mysqlbackup --apply-log phase we extended the spaces
1164 on-demand so that log records could be applied, but that may have
1165 left spaces still too small compared to the size stored in the space
1166 header. */
1167 void meb_extend_tablespaces_to_stored_len();
1168 #endif /* UNIV_HOTBACKUP */
1169
1170 /** Free a tablespace object on which fil_space_detach() was invoked.
1171 There must not be any pending I/O's or flushes on the files.
1172 @param[in,out] space tablespace */
1173 static void space_free_low(fil_space_t *&space);
1174
1175 private:
1176 /** We keep system tablespace files always open; this is important
1177 in preventing deadlocks in this module, as a page read completion
1178 often performs another read from the insert buffer. The insert buffer
1179 is in tablespace TRX_SYS_SPACE, and we cannot end up waiting in this
1180 function.
1181 @param[in] space_id Tablespace ID to look up
1182 @return tablespace instance */
1183 [[nodiscard]] fil_space_t *get_reserved_space(space_id_t space_id);
1184
1185 /** Prepare for truncating a single-table tablespace.
1186 1) Wait for pending operations on the tablespace to stop;
1187 2) Remove all insert buffer entries for the tablespace;
1188 @param[in] space_id Tablespace ID
1189 @param[out] space Instance that maps to the space ID.
1190 @return DB_SUCCESS or error */
1191 [[nodiscard]] dberr_t space_prepare_for_truncate(space_id_t space_id,
1192 fil_space_t *&space);
1193
1194 /** Note that a write IO has completed.
1195 @param[in,out] file File on which a write was completed */
1196 void write_completed(fil_node_t *file);
1197
1198 /** If the tablespace is not on the unflushed list, add it.
1199 @param[in,out] space Tablespace to add */
1200 void add_to_unflushed_list(fil_space_t *space);
1201
1202 /** Check for pending operations.
1203 @param[in] space tablespace
1204 @param[in] count number of attempts so far
1205 @return 0 if no pending operations else count + 1. */
1206 [[nodiscard]] ulint space_check_pending_operations(fil_space_t *space,
1207 ulint count) const;
1208
1209 /** Check for pending IO.
1210 @param[in] space Tablespace to check
1211 @param[in] file File in space list
1212 @param[in] count number of attempts so far
1213 @return 0 if no pending else count + 1. */
1214 [[nodiscard]] ulint check_pending_io(const fil_space_t *space,
1215 const fil_node_t &file,
1216 ulint count) const;
1217
1218 /** First we open the file in the normal mode, no async I/O here, for
1219 simplicity. Then do some checks, and close the file again. NOTE that we
1220 could not use the simple file read function os_file_read() in Windows
1221 to read from a file opened for async I/O!
1222 @param[in,out] file Get the size of this file
1223 @param[in] read_only_mode true if read only mode set
1224 @return DB_SUCCESS or error */
1225 [[nodiscard]] dberr_t get_file_size(fil_node_t *file, bool read_only_mode);
1226
1227 /** Get the AIO mode.
1228 @param[in] req_type IO request type
1229 @param[in] sync true if Synchronous IO
1230 return the AIO mode */
1231 [[nodiscard]] static AIO_mode get_AIO_mode(const IORequest &req_type,
1232 bool sync);
1233
1234 /** Get the file name for IO and the local offset within that file.
1235 @param[in,out] space Tablespace for IO
1236 @param[in,out] page_no The relative page number in the file
1237 @param[out] file File node if DB_SUCCESS, NULL if not
1238 @retval DB_SUCCESS if the file is found with the page_no
1239 @retval DB_ERROR if the file is not found or does not contain the page.
1240 in this case file == nullptr */
1241 [[nodiscard]] static dberr_t get_file_for_io(fil_space_t *space,
1242 page_no_t *page_no,
1243 fil_node_t *&file);
1244
1245 private:
1246 /** Fil_shard ID */
1247 const size_t m_id;
1248
1249 /** Tablespace instances hashed on the space id */
1250 Spaces m_spaces;
1251
1252 /** Tablespace instances hashed on the space name */
1253 Names m_names;
1254
1255 #ifndef UNIV_HOTBACKUP
1256 using Pair = std::pair<space_id_t, fil_space_t *>;
1257 using Deleted_spaces = std::vector<Pair, ut::allocator<Pair>>;
1258
1259 /** Deleted tablespaces. All pages for these tablespaces in the buffer pool
1260 will be passively deleted. They need not be written. Once the reference count
1261 is zero, this fil_space_t can be deleted from m_deleted_spaces and removed
1262 from memory. All reads and writes must be done under the shard mutex. */
1263 Deleted_spaces m_deleted_spaces;
1264 #endif /* !UNIV_HOTBACKUP */
1265
1266 /** Base node for the LRU list of the most recently used open
1267 files with no pending I/O's; if we start an I/O on the file,
1268 we first remove it from this list, and return it to the start
1269 of the list when the I/O ends; the system tablespace file is
1270 not put to this list: it is opened after the startup, and kept
1271 open until shutdown */
1272
1273 File_list m_LRU;
1274
1275 /** Base node for the list of those tablespaces whose files contain unflushed
1276 writes; those spaces have at least one file where modification_counter >
1277 flush_counter */
1278 Space_list m_unflushed_spaces;
1279
1280 /** When we write to a file we increment this by one */
1281 int64_t m_modification_counter;
1282
1283 /** Mutex protecting this shard. */
1284 #ifndef UNIV_HOTBACKUP
1285 mutable ib_mutex_t m_mutex;
1286 #else
1287 mutable meb::Mutex m_mutex;
1288 #endif /* !UNIV_HOTBACKUP */
1289
1290 // Disable copying
1291 Fil_shard(Fil_shard &&) = delete;
1292 Fil_shard(const Fil_shard &) = delete;
1293 Fil_shard &operator=(Fil_shard &&) = delete;
1294 Fil_shard &operator=(const Fil_shard &) = delete;
1295
1296 friend class Fil_system;
1297
1298 public:
1299 // list of spaces kept in this shard
1300 Full_space_list m_space_list;
1301 Rotation_list m_rotation_list;
1302 };
1303
1304 /** The tablespace memory cache */
1305 class Fil_system {
1306 public:
1307 using Fil_shards = std::vector<Fil_shard *>;
1308
1309 /** Constructor.
1310 @param[in] n_shards Number of shards to create
1311 @param[in] max_open Maximum number of open files */
1312 Fil_system(size_t n_shards, size_t max_open);
1313
1314 /** Destructor */
1315 ~Fil_system();
1316
1317 /** Acquire a tablespace when it could be dropped concurrently.
1318 Used by background threads that do not necessarily hold proper locks
1319 for concurrency control.
1320 @param[in] space_id Tablespace ID
1321 @param[in] silent Whether to silently ignore missing tablespaces
1322 @return the tablespace, or nullptr if missing or being deleted */
1323 fil_space_t *space_acquire(space_id_t space_id, bool silent);
1324
1325 /** Fetch the file names opened for a space_id during recovery.
1326 @param[in] space_id Tablespace ID to lookup
1327 @return pair of top level directory scanned and names that map
1328 to space_id or nullptr if not found. */
1329 16999690 [[nodiscard]] Tablespace_dirs::Result get_scanned_filename_by_space_id(
1330 space_id_t space_id) {
1331 16999690 return m_dirs.find_by_id(space_id);
1332 }
1333
1334 /** Fetch the file name opened for an undo space number.
1335 @param[in] space_num undo tablespace numb er to lookup
1336 @param[out] space_id Tablespace ID found
1337 @return pair of top level directory scanned and name that maps
1338 to the space_num or nullptr if not found. */
1339 1477403 [[nodiscard]] Tablespace_dirs::Result get_scanned_filename_by_space_num(
1340 space_id_t space_num, space_id_t &space_id) {
1341 1477403 return (m_dirs.find_by_num(space_num, space_id));
1342 }
1343
1344 /** Fetch the file name opened for a space_id from the file map.
1345 @param[in] space_id tablespace ID
1346 @param[out] name the scanned filename
1347 @return true if the space_id is found. The name is set to an
1348 empty string if the space_id is not found. */
1349 5 [[nodiscard]] bool get_file_by_space_id(space_id_t space_id,
1350 std::string &name) {
1351
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 auto result = get_scanned_filename_by_space_id(space_id);
1352
1353
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (result.second != nullptr) {
1354 /* Duplicates should have been sorted out by now. */
1355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 ut_a(result.second->size() == 1);
1356
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 name = result.first + result.second->front();
1357 5 return true;
1358 }
1359
1360 name = "";
1361 return false;
1362 5 }
1363
1364 /** Fetch the file name opened for an undo space number.
1365 @param[in] space_num undo tablespace number
1366 @param[out] space_id tablespace ID
1367 @param[out] name the scanned filename
1368 @return true if the space_id is found. The name is set to an
1369 empty string if the space_id is not found. */
1370 1477403 [[nodiscard]] bool get_file_by_space_num(space_id_t space_num,
1371 space_id_t &space_id,
1372 std::string &name) {
1373
1/2
✓ Branch 0 taken 1477403 times.
✗ Branch 1 not taken.
1477403 auto result = get_scanned_filename_by_space_num(space_num, space_id);
1374
1375
2/2
✓ Branch 0 taken 23374 times.
✓ Branch 1 taken 1454029 times.
1477403 if (result.second != nullptr) {
1376 /* Duplicates should have been sorted out by now. */
1377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23374 times.
23374 ut_a(result.second->size() == 1);
1378
1/2
✓ Branch 0 taken 23374 times.
✗ Branch 1 not taken.
23374 name = result.first + result.second->front();
1379 23374 return true;
1380 }
1381
1382
1/2
✓ Branch 0 taken 1454029 times.
✗ Branch 1 not taken.
1454029 name = "";
1383 1454029 return false;
1384 1477403 }
1385
1386 /** Erase a tablespace ID and its mapping from the scanned files.
1387 @param[in] space_id Tablespace ID to erase
1388 @return true if successful */
1389 24 [[nodiscard]] bool erase_path(space_id_t space_id) {
1390 24 return m_dirs.erase_path(space_id);
1391 }
1392
1393 /** Add file to old file list. The list is used during 5.7 upgrade failure
1394 to revert back the modified file names. We modify partitioned file names
1395 to lower case.
1396 @param[in] file_path old file name with path */
1397 469 void add_old_file(const std::string &file_path) {
1398 469 m_old_paths.push_back(file_path);
1399 469 }
1400
1401 /** Rename partition files during upgrade.
1402 @param[in] revert if true, revert to old names */
1403 void rename_partition_files(bool revert);
1404
1405 /** Clear all accumulated old files. */
1406 10639 void clear_old_files() { m_old_paths.clear(); }
1407
1408 /** Get the top level directory where this filename was found.
1409 @param[in] path Path to look for.
1410 @return the top level directory under which this file was found. */
1411 [[nodiscard]] const std::string &get_root(const std::string &path) const;
1412
1413 /** Update the DD if any files were moved to a new location.
1414 Free the Tablespace_files instance.
1415 @param[in] read_only_mode true if InnoDB is started in
1416 read only mode.
1417 @return DB_SUCCESS if all OK */
1418 [[nodiscard]] dberr_t prepare_open_for_business(bool read_only_mode);
1419
1420 /** Flush to disk the writes in file spaces possibly cached by the OS
1421 (note: spaces of type FIL_TYPE_TEMPORARY are skipped) */
1422 void flush_file_spaces();
1423
1424 #ifndef UNIV_HOTBACKUP
1425 /** Clean up the shards. */
1426 1333116 void purge() {
1427
2/2
✓ Branch 0 taken 90651881 times.
✓ Branch 1 taken 1333115 times.
91984996 for (auto shard : m_shards) {
1428
1/2
✓ Branch 0 taken 90651880 times.
✗ Branch 1 not taken.
90651881 shard->purge();
1429 }
1430 1333115 }
1431
1432 /** Count how many truncated undo space IDs are still tracked in
1433 the buffer pool and the file_system cache.
1434 @param[in] undo_num undo tablespace number.
1435 @return number of undo tablespaces that are still in memory. */
1436 63301 size_t count_undo_deleted(space_id_t undo_num) {
1437 63301 size_t count = 0;
1438
1439
2/2
✓ Branch 0 taken 4304468 times.
✓ Branch 1 taken 63301 times.
4367769 for (auto shard : m_shards) {
1440 4304468 count += shard->count_undo_deleted(undo_num);
1441 }
1442
1443 63301 return count;
1444 }
1445
1446 /** Check if a particular undo space_id for a page in the buffer pool has
1447 been deleted recently.
1448 Its space_id will be found in Fil_shard::m_deleted_spaces until
1449 Fil:shard::checkpoint removes the fil_space_t from Fil_system.
1450 @param[in] space_id Tablespace ID to check.
1451 @return true if this space_id is in the list of recently deleted spaces. */
1452 bool is_deleted(space_id_t space_id) noexcept {
1453 auto shard = shard_by_id(space_id);
1454
1455 return shard->is_deleted(space_id);
1456 }
1457 #endif /* !UNIV_HOTBACKUP */
1458
1459 /** Fetch the fil_space_t instance that maps to the name.
1460 @param[in] name Tablespace name to lookup
1461 @return tablespace instance or nullptr if not found. */
1462 169842 [[nodiscard]] fil_space_t *get_space_by_name(const char *name) {
1463
2/2
✓ Branch 0 taken 10363649 times.
✓ Branch 1 taken 1356 times.
10365005 for (auto shard : m_shards) {
1464
1/2
✓ Branch 0 taken 10363649 times.
✗ Branch 1 not taken.
10363649 shard->mutex_acquire();
1465
1466
1/2
✓ Branch 0 taken 10363649 times.
✗ Branch 1 not taken.
10363649 auto space = shard->get_space_by_name(name);
1467
1468
1/2
✓ Branch 0 taken 10363649 times.
✗ Branch 1 not taken.
10363649 shard->mutex_release();
1469
1470
2/2
✓ Branch 0 taken 168486 times.
✓ Branch 1 taken 10195163 times.
10363649 if (space != nullptr) {
1471 168486 return space;
1472 }
1473 }
1474
1475 1356 return nullptr;
1476 }
1477
1478 /** Check a space ID against the maximum known tablespace ID.
1479 @param[in] space_id Tablespace ID to check
1480 @return true if it is > than maximum known tablespace ID. */
1481 485808 [[nodiscard]] bool is_greater_than_max_id(space_id_t space_id) const {
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 485808 times.
485808 ut_ad(mutex_owned_all());
1483
1484 485808 return space_id > m_max_assigned_id;
1485 }
1486
1487 /** Update the maximum known tablespace ID.
1488 @param[in] space Tablespace instance */
1489 void set_maximum_space_id(const fil_space_t *space) {
1490 ut_ad(mutex_owned_all());
1491
1492 if (!m_space_id_reuse_warned) {
1493 m_space_id_reuse_warned = true;
1494
1495 ib::warn(ER_IB_MSG_266) << "Allocated tablespace ID " << space->id
1496 << " for " << space->name << ", old maximum"
1497 << " was " << m_max_assigned_id;
1498 }
1499
1500 m_max_assigned_id = space->id;
1501 }
1502
1503 /** Update the maximum known space ID if it's smaller than max_id.
1504 @param[in] space_id Value to set if it's greater */
1505 35334 void update_maximum_space_id(space_id_t space_id) {
1506 35334 mutex_acquire_all();
1507
1508
2/2
✓ Branch 0 taken 11625 times.
✓ Branch 1 taken 23709 times.
35334 if (is_greater_than_max_id(space_id)) {
1509 11625 m_max_assigned_id = space_id;
1510 }
1511
1512 35334 mutex_release_all();
1513 35334 }
1514
1515 /** Assigns a new space id for a new single-table tablespace. This
1516 works simply by incrementing the global counter. If 4 billion ids
1517 is not enough, we may need to recycle ids.
1518 @param[out] space_id Set this to the new tablespace ID
1519 @return true if assigned, false if not */
1520 [[nodiscard]] bool assign_new_space_id(space_id_t *space_id);
1521
1522 /** Allows other threads to advance work while we wait for I/Os to complete.
1523 */
1524 void wait_while_ios_in_progress() const {
1525 #ifndef UNIV_HOTBACKUP
1526 /* Wake the I/O-handler threads to make sure pending I/Os are
1527 performed. */
1528 os_aio_simulated_wake_handler_threads();
1529 #endif /* !UNIV_HOTBACKUP */
1530 /* Give CPU to other threads that keep files opened. */
1531 std::this_thread::sleep_for(std::chrono::milliseconds(1));
1532 }
1533
1534 /** Tries to close a file in all the LRU lists.
1535 The caller must hold the mutex.
1536 @return true if success, false if should retry later */
1537 [[nodiscard]] bool close_file_in_all_LRU();
1538
1539 /** Opens all system tablespace data files in all shards. */
1540 void open_all_system_tablespaces();
1541
1542 /** Close all open files. */
1543 void close_all_files();
1544
1545 /** Returns maximum number of allowed non-LRU files opened for a specified
1546 open files limit. */
1547 static size_t get_limit_for_non_lru_files(size_t open_files_limit);
1548
1549 /** Returns minimum open files limit to be set to allow the specified number
1550 of non-LRU files opened. This is inverse function for the
1551 get_limit_for_non_lru_files. */
1552 size_t get_minimum_limit_for_open_files(
1553 size_t n_files_not_belonging_in_lru) const;
1554
1555 /** Changes the maximum opened files limit.
1556 @param[in,out] new_max_open_files New value for the open files limit. If the
1557 limit cannot be changed, the value is changed to a minimum value recommended.
1558 If there are any concurrent calls to set_open_files_limit in progress, setting
1559 the limit will fail and the new_max_open_files will be set to 0.
1560 @return true if the new limit was set. */
1561 bool set_open_files_limit(size_t &new_max_open_files);
1562
1563 /** Returns maximum number of allowed opened files. */
1564 1981949 size_t get_open_files_limit() const { return m_open_files_limit.get_limit(); }
1565
1566 /** Iterate through all persistent tablespace files
1567 (FIL_TYPE_TABLESPACE) returning the nodes via callback function cbk.
1568 @param[in] f Callback
1569 @return any error returned by the callback function. */
1570 [[nodiscard]] dberr_t iterate(Fil_iterator::Function &f);
1571
1572 /** Rotate the tablespace keys by new master key.
1573 @return the number of tablespaces that failed to rotate. */
1574 [[nodiscard]] size_t encryption_rotate();
1575
1576 /** Reencrypt tablespace keys by current master key. */
1577 void encryption_reencrypt(std::vector<space_id_t> &sid_vector);
1578
1579 /** Detach a space object from the tablespace memory cache.
1580 Closes the tablespace files but does not delete them.
1581 There must not be any pending I/O's or flushes on the files.
1582 @param[in,out] space tablespace */
1583 void space_detach(fil_space_t *space);
1584
1585 /** @return the maximum assigned ID so far */
1586 space_id_t get_max_space_id() const { return m_max_assigned_id; }
1587
1588 /** Lookup the tablespace ID.
1589 @param[in] space_id Tablespace ID to lookup
1590 @return true if the space ID is known. */
1591 [[nodiscard]] bool lookup_for_recovery(space_id_t space_id);
1592
1593 /** Open a tablespace that has a redo log record to apply.
1594 @param[in] space_id Tablespace ID
1595 @return DB_SUCCESS if the open was successful */
1596 [[nodiscard]] dberr_t open_for_recovery(space_id_t space_id);
1597
1598 /** This function should be called after recovery has completed.
1599 Check for tablespace files for which we did not see any
1600 MLOG_FILE_DELETE or MLOG_FILE_RENAME record. These could not
1601 be recovered.
1602 @return true if there were some filenames missing for which we had to
1603 ignore redo log records during the apply phase */
1604 [[nodiscard]] bool check_missing_tablespaces();
1605
1606 /** Note that a file has been relocated.
1607 @param[in] object_id Server DD tablespace ID
1608 @param[in] space_id InnoDB tablespace ID
1609 @param[in] space_name Tablespace name
1610 @param[in] old_path Path to the old location
1611 @param[in] new_path Path scanned from disk */
1612 210 void moved(dd::Object_id object_id, space_id_t space_id,
1613 const char *space_name, const std::string &old_path,
1614 const std::string &new_path) {
1615 auto tuple =
1616
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 std::make_tuple(object_id, space_id, space_name, old_path, new_path);
1617
1618
2/4
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 210 times.
✗ Branch 3 not taken.
210 m_moved.push_back(tuple);
1619 210 }
1620
1621 /** Check if a path is known to InnoDB.
1622 @param[in] path Path to check
1623 @return true if path is known to InnoDB */
1624 16549 bool check_path(const std::string &path) const {
1625 16549 return m_dirs.contains(path);
1626 }
1627
1628 /** Get the list of directories that InnoDB knows about.
1629 @return the list of directories 'dir1;dir2;....;dirN' */
1630 11994 std::string get_dirs() const { return m_dirs.get_dirs(); }
1631
1632 /** Determines if a file belongs to the least-recently-used list.
1633 @param[in] space Tablespace to check
1634 @return true if the file belongs to fil_system->m_LRU mutex. */
1635 [[nodiscard]] static bool space_belongs_in_LRU(const fil_space_t *space);
1636
1637 /** Normalize and save a directory to scan for IBD and IBU datafiles
1638 before recovery.
1639 @param[in] directory Directory to scan
1640 @param[in] is_undo_dir true for an undo directory */
1641 24032 void set_scan_dir(const std::string &directory, bool is_undo_dir) {
1642 24032 m_dirs.set_scan_dir(directory, is_undo_dir);
1643 24032 }
1644
1645 /** Normalize and save a list of directories to scan for IBD and IBU
1646 datafiles before recovery.
1647 @param[in] directories Directories to scan */
1648 95 void set_scan_dirs(const std::string &directories) {
1649 95 m_dirs.set_scan_dirs(directories);
1650 95 }
1651
1652 /** Scan the directories to build the tablespace ID to file name
1653 mapping table. */
1654 11994 dberr_t scan() { return m_dirs.scan(); }
1655
1656 /** Get the tablespace ID from an .ibd and/or an undo tablespace. If the ID is
1657 0 on the first page then try finding the ID with Datafile::find_space_id().
1658 @param[in] filename File name to check
1659 @return s_invalid_space_id if not found, otherwise the space ID */
1660 [[nodiscard]] static space_id_t get_tablespace_id(
1661 const std::string &filename);
1662
1663 /** Fil_shard by space ID.
1664 @param[in] space_id Tablespace ID
1665 @return reference to the shard */
1666 7475465423 [[nodiscard]] Fil_shard *shard_by_id(space_id_t space_id,
1667 uint *index = nullptr) const {
1668 #ifndef UNIV_HOTBACKUP
1669
2/2
✓ Branch 0 taken 2740368698 times.
✓ Branch 1 taken 4735413254 times.
7475465423 if (fsp_is_undo_tablespace(space_id)) {
1670 2740368698 const size_t limit = space_id % UNDO_SHARDS;
1671
1672
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 2740368618 times.
2740368698 if (index) *index = UNDO_SHARDS_START + limit;
1673 2740368698 return m_shards[UNDO_SHARDS_START + limit];
1674 }
1675
1676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5178508982 times.
4735413254 ut_ad(m_shards.size() == MAX_SHARDS);
1677
1678
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 5178508694 times.
5178508982 if (index) *index = space_id % UNDO_SHARDS_START;
1679 5178508982 return m_shards[space_id % UNDO_SHARDS_START];
1680 #else /* !UNIV_HOTBACKUP */
1681 ut_ad(m_shards.size() == 1);
1682
1683 return m_shards[0];
1684 #endif /* !UNIV_HOTBACKUP */
1685 }
1686
1687 2729 MY_NODISCARD Fil_shard *shard_by_index(const uint index) const {
1688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2729 times.
2729 ut_ad(index < m_shards.size());
1689 2729 return m_shards[index];
1690 }
1691
1692 2725 uint get_number_of_shards() const { return m_shards.size(); }
1693
1694 /** Acquire all the mutexes. */
1695 692731 void mutex_acquire_all() const {
1696 #ifdef UNIV_HOTBACKUP
1697 ut_ad(m_shards.size() == 1);
1698 #endif /* UNIV_HOTBACKUP */
1699
1700
2/2
✓ Branch 0 taken 47105704 times.
✓ Branch 1 taken 692731 times.
47798439 for (auto shard : m_shards) {
1701
1/2
✓ Branch 0 taken 47105708 times.
✗ Branch 1 not taken.
47105704 shard->mutex_acquire();
1702 }
1703 692731 }
1704
1705 /** Release all the mutexes. */
1706 692731 void mutex_release_all() const {
1707 #ifdef UNIV_HOTBACKUP
1708 ut_ad(m_shards.size() == 1);
1709 #endif /* UNIV_HOTBACKUP */
1710
1711
2/2
✓ Branch 0 taken 47105708 times.
✓ Branch 1 taken 692731 times.
47798439 for (auto shard : m_shards) {
1712
1/2
✓ Branch 0 taken 47105708 times.
✗ Branch 1 not taken.
47105708 shard->mutex_release();
1713 }
1714 692731 }
1715
1716 #ifdef UNIV_DEBUG
1717
1718 /** Checks the consistency of the tablespace cache.
1719 @return true if ok */
1720 [[nodiscard]] bool validate() const;
1721
1722 /** Check if all mutexes are owned
1723 @return true if all owned. */
1724 485808 [[nodiscard]] bool mutex_owned_all() const {
1725 #ifdef UNIV_HOTBACKUP
1726 ut_ad(m_shards.size() == 1);
1727 #endif /* UNIV_HOTBACKUP */
1728
1729
2/2
✓ Branch 0 taken 33034944 times.
✓ Branch 1 taken 485808 times.
33520752 for (const auto shard : m_shards) {
1730
2/4
✓ Branch 0 taken 33034944 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33034944 times.
33034944 ut_ad(shard->mutex_owned());
1731 }
1732
1733 485808 return true;
1734 }
1735
1736 #endif /* UNIV_DEBUG */
1737
1738 /** Rename a tablespace. Use the space_id to find the shard.
1739 @param[in] space_id tablespace ID
1740 @param[in] old_name old tablespace name
1741 @param[in] new_name new tablespace name
1742 @return DB_SUCCESS on success */
1743 [[nodiscard]] dberr_t rename_tablespace_name(space_id_t space_id,
1744 const char *old_name,
1745 const char *new_name);
1746
1747 /** Free the data structures required for recovery. */
1748 11787 void free_scanned_files() { m_dirs.clear(); }
1749
1750 #ifdef UNIV_HOTBACKUP
1751 /** Extends all tablespaces to the size stored in the space header.
1752 During the mysqlbackup --apply-log phase we extended the spaces
1753 on-demand so that log records could be applied, but that may have
1754 left spaces still too small compared to the size stored in the space
1755 header. */
1756 void meb_extend_tablespaces_to_stored_len() {
1757 ut_ad(m_shards.size() == 1);
1758
1759 /* We use a single shard for MEB. */
1760 auto shard = shard_by_id(SPACE_UNKNOWN);
1761
1762 shard->mutex_acquire();
1763
1764 shard->meb_extend_tablespaces_to_stored_len();
1765
1766 shard->mutex_release();
1767 }
1768
1769 /** Process a file name passed as an input
1770 Wrapper around meb_name_process()
1771 @param[in,out] name absolute path of tablespace file
1772 @param[in] space_id The tablespace ID
1773 @param[in] deleted true if MLOG_FILE_DELETE */
1774 void meb_name_process(char *name, space_id_t space_id, bool deleted);
1775
1776 }
1777 #endif /* UNIV_HOTBACKUP */
1778
1779 private:
1780 /** Open an ibd tablespace and add it to the InnoDB data structures.
1781 This is similar to fil_ibd_open() except that it is used while
1782 processing the redo log, so the data dictionary is not available
1783 and very little validation is done. The tablespace name is extracted
1784 from the dbname/tablename.ibd portion of the filename, which assumes
1785 that the file is a file-per-table tablespace. Any name will do for
1786 now. General tablespace names will be read from the dictionary after
1787 it has been recovered. The tablespace flags are read at this time
1788 from the first page of the file in validate_for_recovery().
1789 @param[in] space_id tablespace ID
1790 @param[in] path path/to/databasename/tablename.ibd
1791 @param[out] space the tablespace, or nullptr on error
1792 @return status of the operation */
1793 [[nodiscard]] fil_load_status ibd_open_for_recovery(space_id_t space_id,
1794 const std::string &path,
1795 fil_space_t *&space);
1796
1797 private:
1798 /** Fil_shards managed */
1799 Fil_shards m_shards;
1800
1801 fil::detail::Open_files_limit m_open_files_limit;
1802
1803 /** Maximum space id in the existing tables, or assigned during
1804 the time mysqld has been up; at an InnoDB startup we scan the
1805 data dictionary and set here the maximum of the space id's of
1806 the tables there */
1807 space_id_t m_max_assigned_id;
1808
1809 /** true if fil_space_create() has issued a warning about
1810 potential space_id reuse */
1811 bool m_space_id_reuse_warned;
1812
1813 /** List of tablespaces that have been relocated. We need to
1814 update the DD when it is safe to do so. */
1815 dd_fil::Tablespaces m_moved;
1816
1817 /** Tablespace directories scanned at startup */
1818 Tablespace_dirs m_dirs;
1819
1820 /** Old file paths during 5.7 upgrade. */
1821 std::vector<std::string> m_old_paths;
1822
1823 /** Next index (modulo number of shards) to try to close a file from the LRU
1824 list to distribute closures evenly between the shards. */
1825 std::atomic_size_t m_next_shard_to_close_from_LRU{};
1826
1827 /** Current number of files that are not belonging in LRU. This includes redo
1828 and temporary tablespaces, but not files that were temporarily removed from
1829 the LRU for I/O. */
1830 std::atomic_size_t m_n_files_not_belonging_in_lru{};
1831
1832 /** Throttles messages about high files not belonging in LRU count, the
1833 warning ER_IB_WARN_MANY_NON_LRU_FILES_OPENED. */
1834 ib::Throttler m_MANY_NON_LRU_FILES_OPENED_throttler{};
1835 /** Throttles messages about long waiting for opened files limit, the warning
1836 ER_IB_MSG_TRYING_TO_OPEN_FILE_FOR_LONG_TIME. */
1837 ib::Throttler m_TRYING_TO_OPEN_FILE_FOR_LONG_TIME_throttler{};
1838 /** Throttles messages about accessing space that was already removed, the
1839 warning ACCESSING_NONEXISTINC_SPACE. */
1840 ib::Throttler m_ACCESSING_NONEXISTINC_SPACE_throttler{};
1841
1842 // Disable copying
1843 Fil_system(Fil_system &&) = delete;
1844 Fil_system(const Fil_system &) = delete;
1845 Fil_system &operator=(const Fil_system &) = delete;
1846
1847 friend class Fil_shard;
1848 };
1849
1850 /** The tablespace memory cache. This variable is nullptr before the module is
1851 initialized. */
1852 static Fil_system *fil_system = nullptr;
1853
1854 #ifdef UNIV_HOTBACKUP
1855 static ulint srv_data_read;
1856 static ulint srv_data_written;
1857 #endif /* UNIV_HOTBACKUP */
1858
1859 11945646 static bool is_fast_shutdown() {
1860 #ifndef UNIV_HOTBACKUP
1861
2/2
✓ Branch 0 taken 389413 times.
✓ Branch 1 taken 11556237 times.
12335059 return srv_shutdown_state >= SRV_SHUTDOWN_LAST_PHASE &&
1862
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 389183 times.
12335063 srv_fast_shutdown >= 2;
1863 #else
1864 return false;
1865 #endif
1866 }
1867
1868 543507 bool fil_node_t::can_be_closed() const {
1869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 543508 times.
543507 ut_ad(is_open);
1870 /* We need to wait for the pending extension and I/Os to finish. */
1871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 543508 times.
543508 if (n_pending_ios != 0) {
1872 return false;
1873 }
1874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 543508 times.
543508 if (n_pending_flushes != 0) {
1875 return false;
1876 }
1877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 543508 times.
543508 if (is_being_extended) {
1878 return false;
1879 }
1880 #ifndef UNIV_HOTBACKUP
1881 /* The file must be flushed, unless we are in very fast shutdown process. */
1882
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 543277 times.
543508 if (is_fast_shutdown()) {
1883 230 return true;
1884 }
1885 #endif
1886 543277 return is_flushed();
1887 }
1888
1889 /** Replay a file rename operation if possible.
1890 @param[in] page_id Space ID and first page number in the file
1891 @param[in] old_name old file name
1892 @param[in] new_name new file name
1893 @return whether the operation was successfully applied (the name did not exist,
1894 or new_name did not exist and name was successfully renamed to new_name) */
1895 [[nodiscard]] static bool fil_op_replay_rename(const page_id_t &page_id,
1896 const std::string &old_name,
1897 const std::string &new_name);
1898
1899 #ifndef UNIV_HOTBACKUP
1900 /** Rename partition file.
1901 @param[in] old_path old file path
1902 @param[in] extn file extension suffix
1903 @param[in] revert if true, rename from new to old file
1904 @param[in] import if called during import */
1905 static void fil_rename_partition_file(const std::string &old_path,
1906 ib_file_suffix extn, bool revert,
1907 bool import);
1908 #endif /* !UNIV_HOTBACKUP */
1909
1910 /** Get modified name for partition file. During upgrade we change all
1911 partition files to have lower case separator and partition name.
1912 @param[in] old_path old file name and path
1913 @param[in] extn file extension suffix
1914 @param[out] new_path modified new name for partitioned file
1915 @return true, iff name needs modification. */
1916 static bool fil_get_partition_file(const std::string &old_path,
1917 ib_file_suffix extn, std::string &new_path);
1918
1919 #ifdef UNIV_DEBUG
1920 /** Try fil_validate() every this many times */
1921 static const size_t FIL_VALIDATE_SKIP = 17;
1922 /** Checks the consistency of the tablespace cache some of the time.
1923 @return true if ok or the check was skipped */
1924 178452876 static bool fil_validate_skip() {
1925 /** The fil_validate() call skip counter. Use a signed type
1926 because of the race condition below. */
1927 #ifdef UNIV_HOTBACKUP
1928 static meb::Mutex meb_mutex;
1929
1930 meb_mutex.lock();
1931 #endif /* UNIV_HOTBACKUP */
1932 static int fil_validate_count = FIL_VALIDATE_SKIP;
1933
1934 /* There is a race condition below, but it does not matter,
1935 because this call is only for heuristic purposes. We want to
1936 reduce the call frequency of the costly fil_validate() check
1937 in debug builds. */
1938 178452876 --fil_validate_count;
1939
1940
2/2
✓ Branch 0 taken 167964628 times.
✓ Branch 1 taken 10488248 times.
178452876 if (fil_validate_count > 0) {
1941 #ifdef UNIV_HOTBACKUP
1942 meb_mutex.unlock();
1943 #endif /* UNIV_HOTBACKUP */
1944 167964628 return true;
1945 }
1946
1947 10488248 fil_validate_count = FIL_VALIDATE_SKIP;
1948 #ifdef UNIV_HOTBACKUP
1949 meb_mutex.unlock();
1950 #endif /* UNIV_HOTBACKUP */
1951
1952 10488248 return fil_validate();
1953 }
1954
1955 /** Validate a shard */
1956 716528932 void Fil_shard::validate() const {
1957 716528932 mutex_acquire();
1958
1959 716528036 size_t n_open = 0;
1960
1961
2/2
✓ Branch 0 taken 285888471 times.
✓ Branch 1 taken 716526128 times.
1002416111 for (auto elem : m_spaces) {
1962 285888539 page_no_t size = 0;
1963 285888539 auto space = elem.second;
1964
1965
2/2
✓ Branch 0 taken 285857572 times.
✓ Branch 1 taken 285886164 times.
571746127 for (const auto &file : space->files) {
1966
4/6
✓ Branch 0 taken 31884500 times.
✓ Branch 1 taken 253973049 times.
✓ Branch 2 taken 31884500 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 285857487 times.
285857549 ut_a(file.is_open || !file.n_pending_ios);
1967
1968
2/2
✓ Branch 0 taken 253973272 times.
✓ Branch 1 taken 31884215 times.
285857487 if (file.is_open) {
1969 253973272 ++n_open;
1970 }
1971
1972 285857487 size += file.size;
1973 }
1974
1975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285888075 times.
285886164 ut_a(space->size == size);
1976 }
1977
1978
1/2
✓ Branch 0 taken 716524653 times.
✗ Branch 1 not taken.
716526128 UT_LIST_CHECK(m_LRU);
1979
1980
6/10
✓ Branch 0 taken 716525065 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 716524796 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 218890190 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 935414777 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 218890152 times.
✓ Branch 9 taken 716524625 times.
935414822 for (auto file : m_LRU) {
1981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218890077 times.
218890104 ut_a(file->is_open);
1982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218890044 times.
218890077 ut_a(file->n_pending_ios == 0);
1983
2/4
✓ Branch 0 taken 218890171 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 218890169 times.
218890044 ut_a(fil_system->space_belongs_in_LRU(file->space));
1984 }
1985
1986 716524625 mutex_release();
1987 716531902 }
1988
1989 /** Checks the consistency of the tablespace cache.
1990 @return true if ok */
1991 10536700 bool Fil_system::validate() const {
1992
2/2
✓ Branch 0 taken 716528354 times.
✓ Branch 1 taken 10537280 times.
727068569 for (const auto shard : m_shards) {
1993
1/2
✓ Branch 0 taken 716531869 times.
✗ Branch 1 not taken.
716528637 shard->validate();
1994 }
1995
1996 10537280 return true;
1997 }
1998 /** Checks the consistency of the tablespace cache.
1999 @return true if ok */
2000 10536525 bool fil_validate() { return fil_system->validate(); }
2001 #endif /* UNIV_DEBUG */
2002
2003 /** Constructor.
2004 @param[in] n_shards Number of shards to create
2005 @param[in] max_open Maximum number of open files */
2006 12330 Fil_system::Fil_system(size_t n_shards, size_t max_open)
2007 12330 : m_shards(),
2008
1/2
✓ Branch 0 taken 12330 times.
✗ Branch 1 not taken.
12330 m_open_files_limit(max_open),
2009 12330 m_max_assigned_id(),
2010 12330 m_space_id_reuse_warned() {
2011
2/2
✓ Branch 0 taken 838440 times.
✓ Branch 1 taken 12330 times.
850770 for (size_t i = 0; i < n_shards; ++i) {
2012
1/2
✓ Branch 0 taken 838440 times.
✗ Branch 1 not taken.
838440 auto shard = ut::new_withkey<Fil_shard>(UT_NEW_THIS_FILE_PSI_KEY, i);
2013
2014
1/2
✓ Branch 0 taken 838440 times.
✗ Branch 1 not taken.
838440 m_shards.push_back(shard);
2015 }
2016 12330 }
2017
2018 /** Destructor */
2019 10639 Fil_system::~Fil_system() {
2020
2/2
✓ Branch 0 taken 723452 times.
✓ Branch 1 taken 10639 times.
734091 for (auto shard : m_shards) {
2021 723452 ut::delete_(shard);
2022 }
2023
2024 10639 m_shards.clear();
2025 10639 }
2026
2027 /** Determines if a file belongs to the least-recently-used list.
2028 @param[in] space Tablespace to check
2029 @return true if the file belongs to fil_system->m_LRU mutex. */
2030 364528087 bool Fil_system::space_belongs_in_LRU(const fil_space_t *space) {
2031
2/3
✓ Branch 0 taken 245446625 times.
✓ Branch 1 taken 119085765 times.
✗ Branch 2 not taken.
364528087 switch (space->purpose) {
2032 245446625 case FIL_TYPE_TABLESPACE:
2033
2/2
✓ Branch 0 taken 242471928 times.
✓ Branch 1 taken 2974231 times.
487923385 return !fsp_is_system_tablespace(space->id) &&
2034
2/2
✓ Branch 0 taken 149718825 times.
✓ Branch 1 taken 92757935 times.
487922919 !fsp_is_undo_tablespace(space->id);
2035
2036 119085765 case FIL_TYPE_TEMPORARY:
2037 case FIL_TYPE_IMPORT:
2038 119085765 return true;
2039 }
2040
2041 ut_d(ut_error);
2042 ut_o(return false);
2043 }
2044
2045 /** Constructor
2046 @param[in] shard_id Shard ID */
2047 838440 Fil_shard::Fil_shard(size_t shard_id)
2048 838440 : m_id(shard_id),
2049 838440 m_spaces(),
2050 838440 m_names(),
2051 838440 m_LRU(),
2052 838440 m_unflushed_spaces(),
2053 838440 m_modification_counter(),
2054 838440 m_space_list(),
2055
2/4
✓ Branch 0 taken 838440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 838440 times.
✗ Branch 3 not taken.
2515320 m_rotation_list() {
2056
1/2
✓ Branch 0 taken 838440 times.
✗ Branch 1 not taken.
838440 mutex_create(LATCH_ID_FIL_SHARD, &m_mutex);
2057 838440 }
2058
2059 /** Map the space ID and name to the tablespace instance.
2060 @param[in] space Tablespace instance */
2061 450474 void Fil_shard::space_add(fil_space_t *space, fil_encryption_t mode) {
2062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450474 times.
450474 ut_ad(mutex_owned());
2063
2064 {
2065
1/2
✓ Branch 0 taken 450474 times.
✗ Branch 1 not taken.
450474 auto it = m_spaces.insert(Spaces::value_type(space->id, space));
2066
2067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450474 times.
450474 ut_a(it.second);
2068 }
2069
2070 {
2071 450474 auto name = space->name;
2072
2073
1/2
✓ Branch 0 taken 450474 times.
✗ Branch 1 not taken.
450474 auto it = m_names.insert(Names::value_type(name, space));
2074
2075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450474 times.
450474 ut_a(it.second);
2076 }
2077
2078 450474 UT_LIST_ADD_LAST(m_space_list, space);
2079
2080 /* Inform key rotation that there could be something
2081 to do */
2082
3/4
✓ Branch 0 taken 318289 times.
✓ Branch 1 taken 132185 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 318289 times.
450474 if (space->purpose == FIL_TYPE_TABLESPACE && !srv_fil_crypt_rotate_key_age &&
2083 fil_crypt_threads_event &&
2084 (mode == FIL_ENCRYPTION_ON ||
2085 (mode == FIL_ENCRYPTION_DEFAULT &&
2086 srv_default_table_encryption == DEFAULT_TABLE_ENC_ONLINE_TO_KEYRING))) {
2087 /* Key rotation is not enabled, need to inform background
2088 encryption threads. */
2089 UT_LIST_ADD_LAST(m_rotation_list, space);
2090 space->is_in_rotation_list = true;
2091 mutex_enter(&fil_crypt_threads_mutex);
2092 os_event_set(fil_crypt_threads_event);
2093 mutex_exit(&fil_crypt_threads_mutex);
2094 }
2095 450474 }
2096
2097 72475176 void Fil_shard::add_to_lru_if_needed(fil_node_t *file) {
2098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72475284 times.
72475176 ut_ad(mutex_owned());
2099
2100
2/2
✓ Branch 0 taken 24649716 times.
✓ Branch 1 taken 47825455 times.
72475284 if (Fil_system::space_belongs_in_LRU(file->space)) {
2101 24649716 UT_LIST_ADD_FIRST(m_LRU, file);
2102 }
2103 72475207 }
2104
2105 /** Remove the file node from the LRU list.
2106 @param[in,out] file File for the tablespace */
2107 72447442 void Fil_shard::remove_from_LRU(fil_node_t *file) {
2108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72447780 times.
72447442 ut_ad(mutex_owned());
2109
2110
2/2
✓ Branch 0 taken 24627133 times.
✓ Branch 1 taken 47820661 times.
72447780 if (Fil_system::space_belongs_in_LRU(file->space)) {
2111 /* The file is in the LRU list, remove it */
2112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24627114 times.
24627133 ut_ad(ut_list_exists(m_LRU, file));
2113 24627114 UT_LIST_REMOVE(m_LRU, file);
2114 }
2115 72447821 }
2116
2117 /** Close a tablespace file based on tablespace ID.
2118 @param[in] space_id Tablespace ID
2119 @return false if space_id was not found. */
2120 211077 bool Fil_shard::close_file(space_id_t space_id) {
2121 211077 mutex_acquire();
2122
2123 211077 auto space = get_space_by_id(space_id);
2124
2125
2/2
✓ Branch 0 taken 103519 times.
✓ Branch 1 taken 107558 times.
211077 if (space == nullptr) {
2126 103519 mutex_release();
2127
2128 103519 return false;
2129 }
2130
2131
2/2
✓ Branch 0 taken 107558 times.
✓ Branch 1 taken 107558 times.
215116 for (auto &file : space->files) {
2132
5/8
✓ Branch 0 taken 107129 times.
✓ Branch 1 taken 429 times.
✓ Branch 2 taken 107129 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 107129 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 107558 times.
107558 while (file.is_open && !file.can_be_closed()) {
2133 mutex_release();
2134
2135 std::this_thread::sleep_for(std::chrono::milliseconds(10));
2136
2137 mutex_acquire();
2138 }
2139
2140
2/2
✓ Branch 0 taken 107129 times.
✓ Branch 1 taken 429 times.
107558 if (file.is_open) {
2141
1/2
✓ Branch 0 taken 107129 times.
✗ Branch 1 not taken.
107129 close_file(&file);
2142 }
2143 }
2144
2145 107558 mutex_release();
2146
2147 107558 return true;
2148 }
2149
2150 /** Remap the tablespace to the new name.
2151 @param[in] space Tablespace instance, with old name.
2152 @param[in] new_name New tablespace name */
2153 103924 void Fil_shard::update_space_name_map(fil_space_t *space,
2154 const char *new_name) {
2155
2/4
✓ Branch 0 taken 103924 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103924 times.
103924 ut_ad(mutex_owned());
2156
2157
2/4
✓ Branch 0 taken 103924 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103924 times.
103924 ut_ad(m_spaces.find(space->id) != m_spaces.end());
2158
2159
1/2
✓ Branch 0 taken 103924 times.
✗ Branch 1 not taken.
103924 m_names.erase(space->name);
2160
2161
1/2
✓ Branch 0 taken 103924 times.
✗ Branch 1 not taken.
103924 auto it = m_names.insert(Names::value_type(new_name, space));
2162
2163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103924 times.
103924 ut_a(it.second);
2164 103924 }
2165
2166 /** Check if the basename of a filepath is an undo tablespace name
2167 @param[in] name Tablespace name
2168 @return true if it is an undo tablespace name */
2169 2055858 bool Fil_path::is_undo_tablespace_name(const std::string &name) {
2170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2055858 times.
2055858 if (name.empty()) {
2171 return false;
2172 }
2173
2174
1/2
✓ Branch 0 taken 2055858 times.
✗ Branch 1 not taken.
2055858 std::string basename = Fil_path::get_basename(name);
2175
2176 2055858 const auto end = basename.end();
2177
2178 /* 5 is the minimum length for an explicit undo space name.
2179 It must be at least this long; "_.ibu". */
2180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2055858 times.
2055858 if (basename.length() <= strlen(DOT_IBU)) {
2181 return false;
2182 }
2183
2184 /* Implicit undo names can come in two formats: undo_000 and undo000.
2185 Check for both. */
2186
2/2
✓ Branch 0 taken 372347 times.
✓ Branch 1 taken 1683511 times.
2055858 size_t u = (*(end - 4) == '_') ? 1 : 0;
2187
2188 2055858 if (basename.length() == sizeof("undo000") - 1 + u &&
2189
2/2
✓ Branch 0 taken 23183 times.
✓ Branch 1 taken 12022 times.
35205 *(end - 7 - u) == 'u' && /* 'u' */
2190
1/2
✓ Branch 0 taken 23183 times.
✗ Branch 1 not taken.
23183 *(end - 6 - u) == 'n' && /* 'n' */
2191
1/2
✓ Branch 0 taken 23183 times.
✗ Branch 1 not taken.
23183 *(end - 5 - u) == 'd' && /* 'd' */
2192
1/2
✓ Branch 0 taken 23183 times.
✗ Branch 1 not taken.
23183 *(end - 4 - u) == 'o' && /* 'o' */
2193
1/2
✓ Branch 0 taken 23183 times.
✗ Branch 1 not taken.
23183 isdigit(*(end - 3)) && /* 'n' */
2194
3/4
✓ Branch 0 taken 35205 times.
✓ Branch 1 taken 2020653 times.
✓ Branch 2 taken 23183 times.
✗ Branch 3 not taken.
2114246 isdigit(*(end - 2)) && /* 'n' */
2195
3/4
✓ Branch 0 taken 23183 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23183 times.
✓ Branch 3 taken 2032675 times.
2079041 isdigit(*(end - 1))) { /* 'n' */
2196 23183 return true;
2197 }
2198
2199
3/4
✓ Branch 0 taken 2032675 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 286 times.
✓ Branch 3 taken 2032389 times.
2032675 if (basename.substr(basename.length() - 4, 4) == DOT_IBU) {
2200 286 return true;
2201 }
2202
2203 2032389 return false;
2204 2055858 }
2205
2206 /** Add a space ID to filename mapping.
2207 @param[in] space_id Tablespace ID
2208 @param[in] name File name.
2209 @return number of files that map to the space ID */
2210 110309 size_t Tablespace_files::add(space_id_t space_id, const std::string &name) {
2211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110309 times.
110309 ut_a(space_id != TRX_SYS_SPACE);
2212
2213 Names *names;
2214
2215
2/2
✓ Branch 0 taken 23464 times.
✓ Branch 1 taken 86845 times.
110309 if (undo::is_reserved(space_id)) {
2216
3/6
✓ Branch 0 taken 23464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23464 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23464 times.
23464 ut_ad(!Fil_path::has_suffix(IBD, name.c_str()));
2217
2218 /* Use m_undo_nums to allow a reserved undo space ID
2219 to be found quickly. */
2220 23464 space_id_t space_num = undo::id2num(space_id);
2221
1/2
✓ Branch 0 taken 23464 times.
✗ Branch 1 not taken.
23464 m_undo_nums[space_num] = space_id;
2222
2223
1/2
✓ Branch 0 taken 23464 times.
✗ Branch 1 not taken.
23464 names = &m_undo_paths[space_id];
2224
2225 } else {
2226
3/6
✓ Branch 0 taken 86845 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 86845 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 86845 times.
86845 ut_ad(!Fil_path::has_suffix(IBU, name.c_str()));
2227
2228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 86845 times.
86845 if (0 == strncmp(name.c_str(), "undo_", 5)) {
2229 ib::warn(ER_IB_MSG_267) << "Tablespace '" << name << "' naming"
2230 << " format is like an undo tablespace"
2231 << " but its ID " << space_id << " is not"
2232 << " in the undo tablespace range";
2233 }
2234
2235 86845 names = &m_ibd_paths[space_id];
2236 }
2237
2238 110309 names->push_back(name);
2239
2240 110309 return names->size();
2241 }
2242
2243 /** Reads data from a space to a buffer. Remember that the possible incomplete
2244 blocks at the end of file are ignored: they are not taken into account when
2245 calculating the byte offset within a space.
2246 @param[in] page_id page id
2247 @param[in] page_size page size
2248 @param[in] byte_offset remainder of offset in bytes; in aio this
2249 must be divisible by the OS block size
2250 @param[in] len how many bytes to read; this must not cross a
2251 file boundary; in aio this must be a block size multiple
2252 @param[in,out] buf buffer where to store data read; in aio this
2253 must be appropriately aligned
2254 @return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
2255 i/o on a tablespace which does not exist */
2256 10811 static dberr_t fil_read(const page_id_t &page_id, const page_size_t &page_size,
2257 ulint byte_offset, ulint len, void *buf) {
2258
1/2
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
10811 return fil_io(IORequestRead, true, page_id, page_size, byte_offset, len, buf,
2259 nullptr);
2260 }
2261
2262 /** Writes data to a space from a buffer. Remember that the possible incomplete
2263 blocks at the end of file are ignored: they are not taken into account when
2264 calculating the byte offset within a space.
2265 @param[in] page_id page id
2266 @param[in] page_size page size
2267 @param[in] byte_offset remainder of offset in bytes; in aio this
2268 must be divisible by the OS block size
2269 @param[in] len how many bytes to write; this must not cross
2270 a file boundary; in aio this must be a block size multiple
2271 @param[in] buf buffer from which to write; in aio this must
2272 be appropriately aligned
2273 @return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
2274 I/O on a tablespace which does not exist */
2275 10811 static dberr_t fil_write(const page_id_t &page_id, const page_size_t &page_size,
2276 ulint byte_offset, ulint len, void *buf) {
2277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10811 times.
10811 ut_ad(!srv_read_only_mode);
2278
2279
1/2
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
10811 return fil_io(IORequestWrite, true, page_id, page_size, byte_offset, len, buf,
2280 nullptr);
2281 }
2282
2283 /** Look up a tablespace. The caller should hold an InnoDB table lock or
2284 a MDL that prevents the tablespace from being dropped during the operation,
2285 or the caller should be in single-threaded crash recovery mode (no user
2286 connections that could drop tablespaces). If this is not the case,
2287 fil_space_acquire() and fil_space_release() should be used instead.
2288 @param[in] space_id Tablespace ID
2289 @return tablespace, or nullptr if not found */
2290 165386075 fil_space_t *fil_space_get(space_id_t space_id) {
2291 165386075 auto shard = fil_system->shard_by_id(space_id);
2292
2293 165386626 shard->mutex_acquire();
2294
2295 165386601 fil_space_t *space = shard->get_space_by_id(space_id);
2296
2297 165386440 shard->mutex_release();
2298
2299 165386817 return space;
2300 }
2301
2302 #ifndef UNIV_HOTBACKUP
2303
2304 /** Returns the latch of a file space.
2305 @param[in] space_id Tablespace ID
2306 @return latch protecting storage allocation */
2307 4836745 rw_lock_t *fil_space_get_latch(space_id_t space_id) {
2308 4836745 auto shard = fil_system->shard_by_id(space_id);
2309
2310 4836746 shard->mutex_acquire();
2311
2312 4836747 fil_space_t *space = shard->get_space_by_id(space_id);
2313
2314 4836748 shard->mutex_release();
2315
2316 4836748 return &space->latch;
2317 }
2318
2319 #ifdef UNIV_DEBUG
2320
2321 /** Gets the type of a file space.
2322 @param[in] space_id Tablespace ID
2323 @return file type */
2324 23374502 fil_type_t fil_space_get_type(space_id_t space_id) {
2325 23374502 auto shard = fil_system->shard_by_id(space_id);
2326
2327 23374503 shard->mutex_acquire();
2328
2329 23374502 auto space = shard->get_space_by_id(space_id);
2330
2331 23374500 shard->mutex_release();
2332
2333 23374504 return space->purpose;
2334 }
2335
2336 #endif /* UNIV_DEBUG */
2337
2338 598 void fil_space_set_imported(space_id_t space_id) {
2339 598 auto shard = fil_system->shard_by_id(space_id);
2340
2341 598 shard->mutex_acquire();
2342
2343 598 fil_space_t *space = shard->get_space_by_id(space_id);
2344
2345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598 times.
598 ut_ad(space->purpose == FIL_TYPE_IMPORT);
2346 598 space->purpose = FIL_TYPE_TABLESPACE;
2347
2348 598 shard->mutex_release();
2349 598 }
2350 #endif /* !UNIV_HOTBACKUP */
2351
2352 /** Checks if all the file nodes in a space are flushed. The caller must hold
2353 the fil_system mutex.
2354 @param[in] space Tablespace to check
2355 @return true if all are flushed */
2356 10774720 bool Fil_shard::space_is_flushed(const fil_space_t *space) {
2357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10775256 times.
10774720 ut_ad(mutex_owned());
2358
2359
2/2
✓ Branch 0 taken 10777534 times.
✓ Branch 1 taken 9988051 times.
20766047 for (const auto &file : space->files) {
2360
3/4
✓ Branch 0 taken 10778033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 787242 times.
✓ Branch 3 taken 9990791 times.
10777215 if (!file.is_flushed()) {
2361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 787251 times.
787242 ut_ad(!fil_disable_space_flushing(space));
2362 787251 return false;
2363 }
2364 }
2365
2366 9988051 return true;
2367 }
2368
2369 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
2370
2371 #include <sys/ioctl.h>
2372
2373 /** FusionIO atomic write control info */
2374 #define DFS_IOCTL_ATOMIC_WRITE_SET _IOW(0x95, 2, uint)
2375
2376 /** Try and enable FusionIO atomic writes.
2377 @param[in] file OS file handle
2378 @return true if successful */
2379 220631 bool fil_fusionio_enable_atomic_write(pfs_os_file_t file) {
2380
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 220603 times.
220631 if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
2381 28 uint atomic = 1;
2382
2383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 ut_a(file.m_file != -1);
2384
2385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (ioctl(file.m_file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic) != -1) {
2386 return true;
2387 }
2388 }
2389
2390 220631 return false;
2391 }
2392 #endif /* !NO_FALLOCATE && UNIV_LINUX */
2393
2394 /** Attach a file to a tablespace
2395 @param[in] name file name of a file that is not open
2396 @param[in] size file size in entire database blocks
2397 @param[in,out] space tablespace from fil_space_create()
2398 @param[in] is_raw whether this is a raw device or partition
2399 @param[in] punch_hole true if supported for this file
2400 @param[in] atomic_write true if the file has atomic write enabled
2401 @param[in] max_pages maximum number of pages in file
2402 @return pointer to the file name
2403 @retval nullptr if error */
2404 450501 fil_node_t *Fil_shard::create_node(const char *name, page_no_t size,
2405 fil_space_t *space, bool is_raw,
2406 bool punch_hole, bool atomic_write,
2407 page_no_t max_pages) {
2408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450501 times.
450501 ut_ad(name != nullptr);
2409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450501 times.
450501 ut_ad(fil_system != nullptr);
2410
2411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450501 times.
450501 if (space == nullptr) {
2412 return nullptr;
2413 }
2414
2415 450501 fil_node_t file{};
2416
2417
1/2
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
450501 file.name = mem_strdup(name);
2418
2419
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 450501 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 450501 times.
450501 ut_a(!is_raw || srv_start_raw_disk_in_use);
2420
2421
1/2
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
450501 file.sync_event = os_event_create();
2422
2423 450501 file.is_raw_disk = is_raw;
2424
2425 450501 file.size = size;
2426
2427 450501 file.flush_size = size;
2428
2429 450501 file.magic_n = FIL_NODE_MAGIC_N;
2430
2431 450501 file.init_size = size;
2432
2433 450501 file.max_size = max_pages;
2434
2435 450501 file.space = space;
2436
2437 450501 os_file_stat_t stat_info = os_file_stat_t();
2438
2439 #ifdef UNIV_DEBUG
2440 dberr_t err =
2441 #endif /* UNIV_DEBUG */
2442
2443 450501 os_file_get_status(
2444
1/2
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
450501 file.name, &stat_info, false,
2445
3/4
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131572 times.
✓ Branch 3 taken 318929 times.
450501 fsp_is_system_temporary(space->id) ? true : srv_read_only_mode);
2446
2447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450501 times.
450501 ut_ad(err == DB_SUCCESS);
2448
2449 450501 file.block_size = stat_info.block_size;
2450
2451 /* In this debugging mode, we can overcome the limitation of some
2452 OSes like Windows that support Punch Hole but have a hole size
2453 effectively too large. By setting the block size to be half the
2454 page size, we can bypass one of the checks that would normally
2455 turn Page Compression off. This execution mode allows compression
2456 to be tested even when full punch hole support is not available. */
2457
3/4
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 450485 times.
450501 DBUG_EXECUTE_IF(
2458 "ignore_punch_hole",
2459 file.block_size = std::min(static_cast<ulint>(stat_info.block_size),
2460 UNIV_PAGE_SIZE / 2););
2461
2462
6/8
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 450501 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 449566 times.
✓ Branch 5 taken 935 times.
✓ Branch 6 taken 1475 times.
✓ Branch 7 taken 449026 times.
900067 if (!IORequest::is_punch_hole_supported() || !punch_hole ||
2463
2/2
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 449026 times.
449566 file.block_size >= srv_page_size) {
2464
1/2
✓ Branch 0 taken 1475 times.
✗ Branch 1 not taken.
1475 fil_no_punch_hole(&file);
2465 } else {
2466 449026 file.punch_hole = punch_hole;
2467 }
2468
2469 450501 file.atomic_write = atomic_write;
2470
2471
1/2
✓ Branch 0 taken 450500 times.
✗ Branch 1 not taken.
450501 mutex_acquire();
2472
2473 450500 space->size += size;
2474
2475
1/2
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
450500 space->files.push_back(file);
2476
2477
1/2
✓ Branch 0 taken 450501 times.
✗ Branch 1 not taken.
450501 mutex_release();
2478
2479
6/8
✓ Branch 0 taken 438493 times.
✓ Branch 1 taken 12008 times.
✓ Branch 2 taken 306921 times.
✓ Branch 3 taken 131572 times.
✓ Branch 4 taken 306921 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 450501 times.
450501 ut_a(space->id == TRX_SYS_SPACE || space->purpose == FIL_TYPE_TEMPORARY ||
2480 space->files.size() == 1);
2481
2482 450501 return &space->files.front();
2483 }
2484
2485 /** Attach a file to a tablespace. File must be closed.
2486 @param[in] name file name (file must be closed)
2487 @param[in] size file size in database blocks, rounded
2488 downwards to an integer
2489 @param[in,out] space space where to append
2490 @param[in] is_raw true if a raw device or a raw disk partition
2491 @param[in] atomic_write true if the file has atomic write enabled
2492 @param[in] max_pages maximum number of pages in file
2493 @return pointer to the file name
2494 @retval nullptr if error */
2495 44460 char *fil_node_create(const char *name, page_no_t size, fil_space_t *space,
2496 bool is_raw, bool atomic_write, page_no_t max_pages) {
2497 44460 auto shard = fil_system->shard_by_id(space->id);
2498
2499 fil_node_t *file;
2500
2501 133380 file = shard->create_node(name, size, space, is_raw,
2502 44460 IORequest::is_punch_hole_supported(), atomic_write,
2503 max_pages);
2504
2505
1/2
✓ Branch 0 taken 44460 times.
✗ Branch 1 not taken.
44460 return file == nullptr ? nullptr : file->name;
2506 }
2507
2508 84840 dberr_t Fil_shard::get_file_size(fil_node_t *file, bool read_only_mode) {
2509
2/4
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84840 times.
84840 ut_ad(mutex_owned());
2510
2511 bool success;
2512 84840 fil_space_t *space = file->space;
2513
2/4
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84840 times.
84840 ut_ad(mutex_owned());
2514
2515 do {
2516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 ut_a(!file->is_open);
2517
2518
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 file->handle = os_file_create_simple_no_error_handling(
2519 innodb_data_file_key, file->name, OS_FILE_OPEN, OS_FILE_READ_ONLY,
2520 read_only_mode, &success);
2521
2522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 if (!success) {
2523 /* The following call prints an error message */
2524 os_file_get_last_error(true);
2525
2526 ib::warn(ER_IB_MSG_268) << "Cannot open '" << file->name
2527 << "'."
2528 " Have you deleted .ibd files under a"
2529 " running mysqld server?";
2530
2531 return DB_ERROR;
2532 }
2533
2534
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 } while (!success);
2535
2536
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 os_offset_t size_bytes = os_file_get_size(file->handle);
2537
2538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 ut_a(size_bytes != (os_offset_t)-1);
2539
2540 #ifdef UNIV_HOTBACKUP
2541 if (space->id == TRX_SYS_SPACE) {
2542 file->size = (ulint)(size_bytes / UNIV_PAGE_SIZE);
2543 space->size += file->size;
2544 os_file_close(file->handle);
2545 return DB_SUCCESS;
2546 }
2547 #endif /* UNIV_HOTBACKUP */
2548
2549 /* Align memory for file I/O if we might have O_DIRECT set */
2550 const ulint buf_size =
2551
2/2
✓ Branch 0 taken 10762 times.
✓ Branch 1 taken 74078 times.
84840 recv_recovery_is_on() ? (UNIV_PAGE_SIZE * 2) : UNIV_PAGE_SIZE;
2552 84840 auto page = static_cast<byte *>(ut::aligned_alloc(buf_size, UNIV_PAGE_SIZE));
2553
2554
2/4
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84840 times.
84840 ut_ad(page == page_align(page));
2555
2556 /* Read the first page of the tablespace */
2557
2558
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 IORequest request(IORequest::READ);
2559
2560
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 dberr_t err = os_file_read_first_page(request, file->name, file->handle, page,
2561 buf_size);
2562
2563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 ut_a(err == DB_SUCCESS);
2564
2565
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 os_file_close(file->handle);
2566
2567
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 uint32_t flags = fsp_header_get_flags(page);
2568
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 space_id_t space_id = fsp_header_get_space_id(page);
2569
2570 /* To determine if tablespace is from 5.7 or not, we
2571 rely on SDI flag. For IBDs from 5.7, which are opened
2572 during import or during upgrade, their initial size
2573 is lesser than the initial size in 8.0 */
2574 84840 bool has_sdi = FSP_FLAGS_HAS_SDI(flags);
2575
2576
2/2
✓ Branch 0 taken 55591 times.
✓ Branch 1 taken 29249 times.
84840 uint8_t expected_size =
2577 has_sdi ? FIL_IBD_FILE_INITIAL_SIZE : FIL_IBD_FILE_INITIAL_SIZE_5_7;
2578
2579
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 const page_size_t page_size(flags);
2580
2581
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 ulint min_size = expected_size * page_size.physical();
2582
2583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 if (size_bytes < min_size) {
2584 if (has_sdi) {
2585 /** Add some tolerance when the tablespace is upgraded. If an empty
2586 general tablespace is created in 5.7, and then upgraded to 8.0, then
2587 its size changes from FIL_IBD_FILE_INITIAL_SIZE_5_7 pages to
2588 FIL_IBD_FILE_INITIAL_SIZE-1. */
2589
2590 ut_ad(expected_size == FIL_IBD_FILE_INITIAL_SIZE);
2591 ulint upgrade_size = (expected_size - 1) * page_size.physical();
2592
2593 if (size_bytes < upgrade_size) {
2594 ib::error(ER_IB_MSG_269)
2595 << "The size of tablespace file " << file->name << " is only "
2596 << size_bytes << ", should be at least " << upgrade_size << "!";
2597
2598 ut_error;
2599 }
2600
2601 } else {
2602 ib::error(ER_IB_MSG_269)
2603 << "The size of tablespace file " << file->name << " is only "
2604 << size_bytes << ", should be at least " << min_size << "!";
2605
2606 ut_error;
2607 }
2608 }
2609
2610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 if (space_id != space->id) {
2611 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_270)
2612 << "Tablespace id is " << space->id
2613 << " in the data dictionary but in file " << file->name << " it is "
2614 << space_id << "!";
2615 }
2616
2617 /* We need to adjust for compressed pages. */
2618
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 const page_size_t space_page_size(space->flags);
2619
2620
2/4
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84840 times.
84840 if (!page_size.equals_to(space_page_size)) {
2621 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_271)
2622 << "Tablespace file " << file->name << " has page size " << page_size
2623 << " (flags=" << ib::hex(flags) << ") but the data dictionary expects"
2624 << " page size " << space_page_size
2625 << " (flags=" << ib::hex(space->flags) << ")!";
2626 }
2627
2628 /* Make the SDI flag in space->flags reflect the SDI flag in the header
2629 page. Maybe this space was discarded before a reboot and then replaced
2630 with a 5.7 space that needs to be imported and upgraded. */
2631 84840 fsp_flags_unset_sdi(space->flags);
2632 84840 space->flags |= flags & FSP_FLAGS_MASK_SDI;
2633
2634 /* Data dictionary and tablespace are flushed at different points in
2635 time. If a crash happens in between, they can have different
2636 encryption flags as long as the redo log is not replayed. To avoid a
2637 recovery error due to differing encryption flags, ensure that the
2638 fil_space_t instance has the same setting as the header page. First
2639 clear the encryption flag, then set it from the flags found in the
2640 file.
2641 It is also possible that for tables, general tablespaces encryption flag
2642 is updated in DD but server crashed before encryption flag is updated on
2643 disk.
2644 Below we print warning in such case. */
2645
6/6
✓ Branch 0 taken 84839 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10761 times.
✓ Branch 3 taken 74078 times.
✓ Branch 4 taken 10761 times.
✓ Branch 5 taken 74079 times.
84840 if (space->crypt_data == nullptr && recv_recovery_is_on()) {
2646 10761 fsp_flags_unset_encryption(space->flags);
2647 10761 space->flags |= flags & FSP_FLAGS_MASK_ENCRYPTION;
2648 }
2649
2650 /* Make a copy of space->flags and flags from the page header
2651 so that they can be compared. */
2652 /* Do not compare the data directory flag, in case this tablespace was
2653 relocated. */
2654 84840 auto fil_space_flags = space->flags & ~FSP_FLAGS_MASK_DATA_DIR;
2655 84840 auto header_fsp_flags = flags & ~FSP_FLAGS_MASK_DATA_DIR;
2656
2657 // in case of Keyring encryption it can so happen that there will be a crash
2658 // after all pages of tablespace is rotated and DD is updated, but page0 of
2659 // the tablespace has not been yet update. We handle this here.
2660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (space->crypt_data != nullptr &&
2661 1 ((FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) &&
2662
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 space->crypt_data->min_key_version == 0) ||
2663 1 (!FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) &&
2664
4/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 84839 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 84840 times.
84841 space->crypt_data->min_key_version != 0)) &&
2665 FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) !=
2666 FSP_FLAGS_GET_ENCRYPTION(header_fsp_flags)) {
2667 if (srv_n_fil_crypt_threads_requested == 0) {
2668 ib::warn() << "Table encryption flag is "
2669 << (FSP_FLAGS_GET_ENCRYPTION(fil_space_flags) ? "ON" : "OFF")
2670 << " in the data dictionary but the encryption flag in file "
2671 << file->name << " is "
2672 << (FSP_FLAGS_GET_ENCRYPTION(header_fsp_flags) ? "ON" : "OFF")
2673 << ". This indicates that the rotation of the table was "
2674 "interrupted before space's flags were updated."
2675 << " Please have encryption_thread variable "
2676 "(innodb-encryption-threads) set to value > 0. So the "
2677 "encryption"
2678 << " could finish up the rotation.";
2679 }
2680 // exclude encryption flag from validation
2681 fsp_flags_unset_encryption(fil_space_flags);
2682 fsp_flags_unset_encryption(header_fsp_flags);
2683 }
2684
2685 /* Make sure the space_flags are the same as the header page flags. */
2686
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 if (UNIV_UNLIKELY(fil_space_flags != header_fsp_flags)) {
2687 ib::error(ER_IB_MSG_272, ulong{space->flags}, file->name, ulonglong{flags});
2688 ut_error;
2689 }
2690
2691 {
2692
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 page_no_t size = fsp_header_get_field(page, FSP_SIZE);
2693
2694 page_no_t free_limit;
2695
2696
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT);
2697
2698 ulint free_len;
2699
2700
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + page);
2701
2702
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84840 times.
84840 ut_ad(space->free_limit == 0 || space->free_limit == free_limit);
2703
2704
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84840 times.
84840 ut_ad(space->free_len == 0 || space->free_len == free_len);
2705
2706 84840 space->size_in_header = size;
2707 84840 space->free_limit = free_limit;
2708
2709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 ut_a(free_len < std::numeric_limits<uint32_t>::max());
2710
2711 84840 space->free_len = (uint32_t)free_len;
2712
2713 /* TODO: Get consistent flag from recovered DD. For that, DD should be
2714 recovered already. */
2715 /* Set estimated value for space->compression_type
2716 during recovery process. */
2717
2718
4/4
✓ Branch 0 taken 10762 times.
✓ Branch 1 taken 74078 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 84815 times.
95602 if (recv_recovery_is_on() &&
2719
4/6
✓ Branch 0 taken 10762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10762 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10747 times.
✓ Branch 5 taken 15 times.
10762 (Compression::is_compressed_page(page + page_size.physical()) ||
2720
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10737 times.
10747 Compression::is_compressed_encrypted_page(page +
2721
2/4
✓ Branch 0 taken 10747 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10747 times.
✗ Branch 3 not taken.
10747 page_size.physical()))) {
2722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 ut_ad(buf_size >= (UNIV_PAGE_SIZE * 2));
2723 Compression::meta_t header;
2724
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
25 Compression::deserialize_header(page + page_size.physical(), &header);
2725 25 space->compression_type = header.m_algorithm;
2726 }
2727 }
2728
2729 84840 ut::aligned_free(page);
2730
2731 /* For encrypted tablespace, we need to check the
2732 encryption key and iv(initial vector) is read. */
2733
5/6
✓ Branch 0 taken 1366 times.
✓ Branch 1 taken 83474 times.
✓ Branch 2 taken 1002 times.
✓ Branch 3 taken 364 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 84840 times.
85842 if (FSP_FLAGS_GET_ENCRYPTION(space->flags) && !recv_recovery_is_on() &&
2734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1002 times.
1002 space->m_encryption_metadata.m_type != Encryption::AES) {
2735 ib::error(ER_IB_MSG_273, file->name);
2736
2737 return DB_ERROR;
2738 }
2739
2740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (space->crypt_data && space->crypt_data->type == CRYPT_SCHEME_1 &&
2741
3/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 84839 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 84840 times.
84841 !space->crypt_data->key_found && !recv_recovery_is_on()) {
2742 ib::error() << "There is no key for tablespace " << space->name;
2743 return (DB_IO_DECRYPT_FAIL);
2744 }
2745
2746
2/2
✓ Branch 0 taken 53717 times.
✓ Branch 1 taken 31123 times.
84840 if (file->size == 0) {
2747 ulint extent_size;
2748
2749
5/6
✓ Branch 0 taken 53717 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53666 times.
✓ Branch 3 taken 51 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 27 times.
53717 extent_size = page_size.physical() * FSP_EXTENT_SIZE;
2750
2751 #ifndef UNIV_HOTBACKUP
2752 /* Truncate the size to a multiple of extent size. */
2753
2/2
✓ Branch 0 taken 16996 times.
✓ Branch 1 taken 36721 times.
53717 if (size_bytes >= extent_size) {
2754 16996 size_bytes = ut_2pow_round(size_bytes, extent_size);
2755 }
2756 #else /* !UNIV_HOTBACKUP */
2757
2758 /* After apply-incremental, tablespaces are not
2759 extended to a whole megabyte. Do not cut off
2760 valid data. */
2761
2762 #endif /* !UNIV_HOTBACKUP */
2763
2764
1/2
✓ Branch 0 taken 53717 times.
✗ Branch 1 not taken.
53717 file->size = static_cast<page_no_t>(size_bytes / page_size.physical());
2765
2766 53717 space->size += file->size;
2767 }
2768
2769 84840 return DB_SUCCESS;
2770 84840 }
2771
2772 42605 size_t Fil_system::get_limit_for_non_lru_files(size_t open_files_limit) {
2773 /* Leave at least 10% of the limit for the LRU files, to not make system too
2774 inefficient in an edge case there is a lot of non-LRU files causing LRU
2775 ones to be constantly closed and opened. The absolute minimum would be a
2776 single slot for LRU files, but it may be very inefficient. Let's make two the
2777 hard limit. */
2778 const size_t minimum_limit_left_for_lru_files =
2779 42605 std::max(2LL, std::llround(0.1 * open_files_limit));
2780 42605 return open_files_limit - minimum_limit_left_for_lru_files;
2781 }
2782
2783 28 size_t Fil_system::get_minimum_limit_for_open_files(
2784 size_t n_files_not_belonging_in_lru) const {
2785 28 size_t result = 0;
2786 /* Start with the most significant bit and iterate till last one. */
2787 28 for (size_t current_bit = ~(std::numeric_limits<size_t>::max() >> 1);
2788
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 28 times.
1820 current_bit; current_bit >>= 1) {
2789
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 1704 times.
1792 if (get_limit_for_non_lru_files(result + current_bit - 1) <
2790 n_files_not_belonging_in_lru) {
2791 88 result += current_bit;
2792 }
2793 }
2794
2795 28 return result;
2796 }
2797
2798 371781 bool Fil_shard::open_file(fil_node_t *file) {
2799 bool success;
2800 371781 fil_space_t *space = file->space;
2801
2802
2/4
✓ Branch 0 taken 371781 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 371781 times.
371781 ut_ad(mutex_owned());
2803
2804 /* This method is not straightforward. The description is included in comments
2805 to different parts of this function. They are best read one after another
2806 in order. */
2807
2808
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371781 times.
371781 ut_a(!file->is_open);
2809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371781 times.
371781 ut_a(file->n_pending_ios == 0);
2810
2811 371781 const auto start_time = std::chrono::steady_clock::now();
2812
2813 /* This method first assures we can open a file. This comes down to assuring a
2814 correct state under locks is present and that opening of this file will not
2815 exceed any limits. Currently we have two limits for open files:
2816 - maximum number of opened files - fil_system->m_open_files_limit,
2817 - maximum number of opened files that can't be closed on request, i.e. are not
2818 part of open files LRU list.
2819
2820 We can ignore the latter iff the file will be part of the LRU.
2821 For each limit we need to comply with, we need to bump the current number of
2822 files within the limit. If the bump succeeds (results in a current number not
2823 larger than the limit value), we have a right to open a file.
2824
2825 When all rights are acquired the `Fil_shard::open_file` opens the file and
2826 returns true. The file opened will naturally count against the limits. After
2827 this happens, the current values of files for the limits are decreased only in
2828 `Fil_shard::close_file`. */
2829
2830 /* We remember if we have already acquired right to open the file against the
2831 total open files limit. */
2832 371781 bool have_right_for_open = false;
2833 /* As well as the right to open the file against limit for files that do not
2834 take part in LRU algorithm. If the file takes part in LRU algorithm, this
2835 is never true. */
2836 371781 bool have_right_for_open_non_lru = false;
2837
2838 /* To acquire a right against a limit, we use this helper function. It
2839 atomically tries to bump the value of supplied reference to a current value
2840 as long as it is below the limit set. Returns true if the right to open is
2841 acquired. */
2842 418113 const auto acquire_right = [](std::atomic<size_t> &counter,
2843 size_t limit) -> bool {
2844 418113 auto current_count = counter.load();
2845
2/2
✓ Branch 0 taken 412585 times.
✓ Branch 1 taken 5533 times.
418118 while (limit > current_count) {
2846
2/2
✓ Branch 0 taken 412584 times.
✓ Branch 1 taken 4 times.
825173 if (counter.compare_exchange_weak(current_count, current_count + 1)) {
2847 412584 return true;
2848 }
2849 }
2850 5533 return false;
2851 };
2852
2853 /* At any point we can decide to release any rights that we have acquired so
2854 far. This will make us unable to open the file now. The
2855 `Fil_shard::open_file()` when returning `false` must assure no rights are
2856 left unreleased - this helper function helps to assure that. */
2857 588 const auto release_rights = [&]() {
2858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (have_right_for_open) {
2859 fil_n_files_open.fetch_sub(1);
2860 have_right_for_open = false;
2861 }
2862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (have_right_for_open_non_lru) {
2863 ut_ad(fil_system->m_n_files_not_belonging_in_lru.load() > 0);
2864 fil_system->m_n_files_not_belonging_in_lru.fetch_sub(1);
2865 have_right_for_open_non_lru = false;
2866 }
2867 372369 };
2868
2869 /* Helper function: In case of repeated errors, we will delay printing of
2870 any messages to log by PRINT_INTERVAL_SECS after the method processing
2871 starts and then print one message per PRINT_INTERVAL_SECS. */
2872 const auto should_print_message =
2873 12222 [&start_time](ib::Throttler &throttler) -> bool {
2874 6111 const auto current_time = std::chrono::steady_clock::now();
2875
3/6
✓ Branch 0 taken 6111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6111 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6111 times.
6111 if (current_time - start_time >= PRINT_INTERVAL) {
2876 return throttler.apply();
2877 }
2878 6111 return false;
2879 371781 };
2880 /* If this is `false`, the file to open will count against the limit for
2881 opened files not taking part in the LRU algorithm. We will need to acquire
2882 a right to open it. */
2883
1/2
✓ Branch 0 taken 371781 times.
✗ Branch 1 not taken.
371781 const bool belongs_to_lru = Fil_system::space_belongs_in_LRU(file->space);
2884
2885 /* We remember the current limit for opened files. If it changes while we are
2886 acquiring the rights, we must ensure we have not caused it to be bumped higher
2887 than the new limit. This double checking works together with double checking
2888 in the `Fil_system::set_open_files_limit` to ensure no race conditions are
2889 possible to leave number of opened files over the limit even in an event of
2890 changing the limit in parallel.
2891
2892 The non-LRU files limit can only change when the main limit for open files is
2893 changed, so we monitor only the main one. */
2894 371781 auto last_open_file_limit = fil_system->get_open_files_limit();
2895
2896 /* This is the main loop. It tries to assure all conditions required to open
2897 the file or causes `open_file` to exit if the file is already opened in
2898 different thread.
2899
2900 At this point, start of each loop and upon exit of the loop (either with
2901 `break` or `return`) the shard's mutex is owned by this thread. However, it
2902 may be released and re-acquired in meantime, for a while, inside this loop. If
2903 we decide to release the mutex, we must execute the loop from begin after
2904 re-acquiring it.
2905
2906 The following is the list of conditions we must fulfill to allow file to be
2907 opened:
2908 1. At any point, if the file becomes open, we just return success. Must be
2909 done under the mutex.
2910
2911 2. At any point, if the space becomes deleted, we just return failure. Must be
2912 done under the mutex.
2913
2914 3. If the file is locked with `space->prevent_file_open`, then release any
2915 rights against the limits acquired so far, and wait till the "lock" is
2916 released. The check must be done under the mutex. But the waiting must be
2917 executed only when we don't own the mutex - it is required by other thread to
2918 release the "lock".
2919
2920 4. Reserve a right within the non-LRU opened files limit. This is conditional
2921 - required only if the file is supposed to not be placed in the opened files
2922 LRU. This is lock-free.
2923
2924 5. Reserve a right within the fil_system->get_open_files_limit(),
2925 unconditionally.
2926
2927 6. Check if the limit value for the opened files have not changed. If it did,
2928 we just release all rights and retry from the beginning.
2929
2930 7. Only then we can proceed with actually opening the file. */
2931 for (;;) {
2932 /* 1. If the file becomes open, we just return success. We own the mutex,
2933 may have some rights already acquired. */
2934
2/4
✓ Branch 0 taken 377890 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 377890 times.
377890 ut_ad(mutex_owned());
2935
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 377880 times.
377890 if (file->is_open) {
2936
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 release_rights();
2937 10 return true;
2938 }
2939
2940 /* 2. If the space becomes deleted, we just return failure. We own the
2941 mutex and may have some rights already acquired.*/
2942
2/4
✓ Branch 0 taken 377880 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 377880 times.
377880 if (space->is_deleted()) {
2943 release_rights();
2944 return false;
2945 }
2946
2947 /* 3. If the file is locked with `space->prevent_file_open`. */
2948
2/2
✓ Branch 0 taken 578 times.
✓ Branch 1 taken 377302 times.
377880 if (space->prevent_file_open) {
2949 /* Someone wants to rename the file. We can't have it opened now.
2950 Give CPU to other thread that renames the file. Release any
2951 rights and the mutex before we go to sleep - we will not need it and
2952 someone else will be able to get these or use the mutex to change the
2953 `space->prevent_file_open`. */
2954
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 mutex_release();
2955
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 release_rights();
2956
2957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 578 times.
578 if (should_print_message(
2958
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 space->m_prevent_file_open_wait_message_throttler)) {
2959 ib::warn(ER_IB_MSG_278, space->name,
2960 (long long)std::chrono::duration_cast<std::chrono::seconds>(
2961 std::chrono::steady_clock::now() - start_time)
2962 .count());
2963 }
2964
2965 #ifndef UNIV_HOTBACKUP
2966 /* Wake the I/O handler threads to make sure pending I/O's are performed
2967 */
2968
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 os_aio_simulated_wake_handler_threads();
2969
2970 #endif /* UNIV_HOTBACKUP */
2971
2972
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 std::this_thread::sleep_for(std::chrono::milliseconds(1));
2973
2974
1/2
✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
578 mutex_acquire();
2975 578 continue;
2976 }
2977 /* 4. We try to acquire required right for non-LRU file, if it is not taking
2978 part in the LRU algorithm. */
2979
3/4
✓ Branch 0 taken 40813 times.
✓ Branch 1 taken 336489 times.
✓ Branch 2 taken 40813 times.
✗ Branch 3 not taken.
377302 if (!(belongs_to_lru || have_right_for_open_non_lru)) {
2980 40813 have_right_for_open_non_lru =
2981
1/2
✓ Branch 0 taken 40813 times.
✗ Branch 1 not taken.
40813 acquire_right(fil_system->m_n_files_not_belonging_in_lru,
2982 Fil_system::get_limit_for_non_lru_files(
2983 fil_system->get_open_files_limit()));
2984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40813 times.
40813 if (!have_right_for_open_non_lru) {
2985 mutex_release();
2986 if (should_print_message(
2987 fil_system->m_MANY_NON_LRU_FILES_OPENED_throttler)) {
2988 ib::warn(ER_IB_WARN_MANY_NON_LRU_FILES_OPENED,
2989 fil_system->m_n_files_not_belonging_in_lru.load(),
2990 fil_system->get_open_files_limit());
2991 }
2992 /* Give CPU to other threads that keep files opened. */
2993 std::this_thread::sleep_for(std::chrono::milliseconds(1));
2994 mutex_acquire();
2995 continue;
2996 }
2997 }
2998
2999 /* 5. We try to acquire required right to open file. */
3000
2/2
✓ Branch 0 taken 377300 times.
✓ Branch 1 taken 2 times.
377302 if (!have_right_for_open) {
3001 377304 have_right_for_open =
3002 377300 acquire_right(fil_n_files_open, fil_system->get_open_files_limit());
3003
2/2
✓ Branch 0 taken 5533 times.
✓ Branch 1 taken 371771 times.
377304 if (!have_right_for_open) {
3004
1/2
✓ Branch 0 taken 5533 times.
✗ Branch 1 not taken.
5533 mutex_release();
3005
3006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5533 times.
5533 if (should_print_message(
3007
1/2
✓ Branch 0 taken 5533 times.
✗ Branch 1 not taken.
5533 fil_system->m_TRYING_TO_OPEN_FILE_FOR_LONG_TIME_throttler)) {
3008 ib::warn warning(
3009 ER_IB_MSG_TRYING_TO_OPEN_FILE_FOR_LONG_TIME,
3010 static_cast<long long>(
3011 std::chrono::duration_cast<std::chrono::seconds>(
3012 std::chrono::steady_clock::now() - start_time)
3013 .count()),
3014 fil_system->get_open_files_limit());
3015 }
3016
3017 /* Flush tablespaces so that we can close modified files in the LRU
3018 list. */
3019
1/2
✓ Branch 0 taken 5533 times.
✗ Branch 1 not taken.
5533 fil_system->flush_file_spaces();
3020
3021
2/4
✓ Branch 0 taken 5531 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5531 times.
5533 if (!fil_system->close_file_in_all_LRU()) {
3022 fil_system->wait_while_ios_in_progress();
3023 }
3024
1/2
✓ Branch 0 taken 5531 times.
✗ Branch 1 not taken.
5531 mutex_acquire();
3025 5531 continue;
3026 5531 }
3027 }
3028
3029 /* 6. Re-check the open files limit value. This is working in tandem with
3030 double checking the limits in the `set_open_files_limit()`. Either this
3031 thread or one executing `set_open_files_limit()` will spot the limit is
3032 exceeded and rollback to a correct state: either restore limit or release
3033 rights. */
3034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371771 times.
371773 if (last_open_file_limit != fil_system->get_open_files_limit()) {
3035 release_rights();
3036 last_open_file_limit = fil_system->get_open_files_limit();
3037 continue;
3038 }
3039 /* 7. If we have all required rights, and checked under the mutex the
3040 file is not open and can be opened, proceed to opening the file. The file
3041 must be opened before we release the mutex again. */
3042 371771 break;
3043 6109 }
3044
3045 /* We have fulfilled all requirements to actually open the file. */
3046
2/4
✓ Branch 0 taken 371771 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 371771 times.
371771 ut_ad(mutex_owned());
3047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371771 times.
371771 ut_ad(!file->is_open);
3048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371770 times.
371771 ut_ad(!space->prevent_file_open);
3049
4/6
✓ Branch 0 taken 40813 times.
✓ Branch 1 taken 330957 times.
✓ Branch 2 taken 40813 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 371770 times.
371770 ut_ad(belongs_to_lru || have_right_for_open_non_lru);
3050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371770 times.
371770 ut_ad(have_right_for_open);
3051
3052 bool read_only_mode;
3053
3054
5/6
✓ Branch 0 taken 371770 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 237661 times.
✓ Branch 3 taken 134109 times.
✓ Branch 4 taken 231 times.
✓ Branch 5 taken 237430 times.
371770 read_only_mode = !fsp_is_system_temporary(space->id) && srv_read_only_mode;
3055
3056
4/4
✓ Branch 0 taken 318053 times.
✓ Branch 1 taken 53717 times.
✓ Branch 2 taken 84840 times.
✓ Branch 3 taken 286930 times.
689823 if (file->size == 0 ||
3057
5/6
✓ Branch 0 taken 43046 times.
✓ Branch 1 taken 275007 times.
✓ Branch 2 taken 31124 times.
✓ Branch 3 taken 11922 times.
✓ Branch 4 taken 31124 times.
✗ Branch 5 not taken.
349177 (space->size_in_header == 0 && space->purpose == FIL_TYPE_TABLESPACE &&
3058 31124 file == &space->files.front()
3059 #ifndef UNIV_HOTBACKUP
3060
4/6
✓ Branch 0 taken 31124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31124 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31123 times.
✓ Branch 5 taken 1 times.
31124 && undo::is_active(space->id, false) &&
3061 srv_startup_is_before_trx_rollback_phase
3062 #endif /* !UNIV_HOTBACKUP */
3063 )) {
3064 /* We don't know the file size yet. */
3065
1/2
✓ Branch 0 taken 84840 times.
✗ Branch 1 not taken.
84840 dberr_t err = get_file_size(file, read_only_mode);
3066
3067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84840 times.
84840 if (err != DB_SUCCESS) {
3068 /* Release the rights acquired as we failed to open it in the end.
3069 */
3070 release_rights();
3071 return false;
3072 }
3073 }
3074
3075 /* Open the file for reading and writing, in Windows normally in the
3076 unbuffered async I/O mode, though global variables may make os_file_create()
3077 to fall back to the normal file I/O mode. */
3078
3079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 371770 times.
371770 if (file->is_raw_disk) {
3080 file->handle =
3081 os_file_create(innodb_data_file_key, file->name, OS_FILE_OPEN_RAW,
3082 OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
3083 } else {
3084 file->handle =
3085
1/2
✓ Branch 0 taken 371771 times.
✗ Branch 1 not taken.
371770 os_file_create(innodb_data_file_key, file->name, OS_FILE_OPEN,
3086 OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
3087 }
3088
3089
1/2
✓ Branch 0 taken 371771 times.
✗ Branch 1 not taken.
371771 if (success) {
3090
1/2
✓ Branch 0 taken 371770 times.
✗ Branch 1 not taken.
371771 add_to_lru_if_needed(file);
3091 /* The file is ready for IO. */
3092 371770 file->is_open = true;
3093 } else {
3094 /* Release the rights acquired as we failed to open it in the end. */
3095 release_rights();
3096 }
3097
3098 /* We exit with the mutex acquired. The file is assured to remain open only as
3099 long as the mutex is held. Calls, like to `prepare_file_for_io()` are
3100 required to continue to use the file with the mutex released. */
3101 371770 return success;
3102 }
3103
3104 344284 void Fil_shard::close_file(fil_node_t *file) {
3105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344285 times.
344284 ut_ad(mutex_owned());
3106
3107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344285 times.
344285 ut_a(file->can_be_closed());
3108
3109 344285 bool ret = os_file_close(file->handle);
3110
3111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344285 times.
344285 ut_a(ret);
3112
3113 344285 file->handle.m_file = (os_file_t)-1;
3114
3115 344285 file->is_open = false;
3116
3117 344285 auto old_files_open_count = fil_n_files_open.fetch_sub(1);
3118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344285 times.
344285 ut_a(old_files_open_count > 0);
3119
3120
2/2
✓ Branch 0 taken 35932 times.
✓ Branch 1 taken 308352 times.
344285 if (!Fil_system::space_belongs_in_LRU(file->space)) {
3121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35932 times.
71864 ut_ad(fil_system->m_n_files_not_belonging_in_lru.load() > 0);
3122
3123 35932 fil_system->m_n_files_not_belonging_in_lru.fetch_sub(1);
3124 }
3125
3126 344284 remove_from_LRU(file);
3127 344285 }
3128
3129 22302 bool Fil_shard::close_files_in_LRU() {
3130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22302 times.
22302 ut_ad(mutex_owned());
3131
3132
2/2
✓ Branch 0 taken 5557 times.
✓ Branch 1 taken 16745 times.
22302 for (auto file = UT_LIST_GET_LAST(m_LRU); file != nullptr;
3133 file = UT_LIST_GET_PREV(LRU, file)) {
3134
1/2
✓ Branch 0 taken 5557 times.
✗ Branch 1 not taken.
5557 if (file->can_be_closed()) {
3135 5557 close_file(file);
3136
3137 5558 return true;
3138 }
3139 }
3140
3141 16745 return false;
3142 }
3143
3144 5558 bool Fil_system::close_file_in_all_LRU() {
3145 5558 const auto n_shards = m_shards.size();
3146 5558 const auto index = m_next_shard_to_close_from_LRU++;
3147
1/2
✓ Branch 0 taken 22302 times.
✗ Branch 1 not taken.
22302 for (size_t i = 0; i < n_shards; ++i) {
3148 22302 auto shard = m_shards[(index + i) % n_shards];
3149 22302 shard->mutex_acquire();
3150
3151 22302 bool success = shard->close_files_in_LRU();
3152
3153 22302 shard->mutex_release();
3154
3155
2/2
✓ Branch 0 taken 5557 times.
✓ Branch 1 taken 16745 times.
22302 if (success) {
3156 5557 return true;
3157 }
3158 }
3159
3160 return false;
3161 }
3162
3163 534696059 fil_space_t *Fil_shard::get_space_by_id(space_id_t space_id) const {
3164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1407600199 times.
534696059 ut_ad(mutex_owned());
3165
3166
2/2
✓ Branch 0 taken 10612375 times.
✓ Branch 1 taken 1396987824 times.
1407600199 if (space_id == TRX_SYS_SPACE) {
3167 10612375 return fil_space_t::s_sys_space;
3168 }
3169
3170 1396987824 return get_space_by_id_from_map(space_id);
3171 }
3172
3173 /** Prepare to free a file. Remove from the unflushed list if there
3174 are no pending flushes.
3175 @param[in,out] file File instance to free */
3176 76701 void Fil_shard::prepare_to_free_file(fil_node_t *file) {
3177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76701 times.
76701 ut_ad(mutex_owned());
3178
3179 76701 fil_space_t *space = file->space;
3180
3181
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 76701 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 76701 times.
76701 if (space->is_in_unflushed_spaces && space_is_flushed(space)) {
3182 space->is_in_unflushed_spaces = false;
3183
3184 UT_LIST_REMOVE(m_unflushed_spaces, space);
3185 }
3186 76701 }
3187
3188 /** Prepare to free a file object from a tablespace memory cache.
3189 @param[in,out] file Tablespace file
3190 @param[in] space tablespace */
3191 413430 void Fil_shard::file_close_to_free(fil_node_t *file, fil_space_t *space) {
3192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413430 times.
413430 ut_ad(mutex_owned());
3193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413430 times.
413430 ut_a(file->magic_n == FIL_NODE_MAGIC_N);
3194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413430 times.
413430 ut_a(file->n_pending_ios == 0);
3195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413430 times.
413430 ut_a(!file->is_being_extended);
3196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413430 times.
413430 ut_a(file->space == space);
3197
3198
2/2
✓ Branch 0 taken 76701 times.
✓ Branch 1 taken 336729 times.
413430 if (file->is_open) {
3199 /* We fool the assertion in Fil_system::close_file() to think
3200 there are no unflushed modifications in the file */
3201
3202 76701 file->set_flushed();
3203
3204 76701 os_event_set(file->sync_event);
3205
3206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76701 times.
76701 if (fil_disable_space_flushing(space)) {
3207 ut_ad(!space->is_in_unflushed_spaces);
3208 ut_ad(space_is_flushed(space));
3209
3210 } else {
3211 76701 prepare_to_free_file(file);
3212 }
3213
3214 76701 close_file(file);
3215 }
3216 413430 }
3217
3218 413406 void Fil_shard::space_detach(fil_space_t *space) {
3219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413406 times.
413406 ut_ad(mutex_owned());
3220
3221 413406 m_names.erase(space->name);
3222
3223
2/2
✓ Branch 0 taken 514 times.
✓ Branch 1 taken 412892 times.
413406 if (space->is_in_unflushed_spaces) {
3224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 ut_ad(!fil_disable_space_flushing(space));
3225
3226 514 space->is_in_unflushed_spaces = false;
3227
3228 514 UT_LIST_REMOVE(m_unflushed_spaces, space);
3229 }
3230
3231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413406 times.
413406 if (space->is_in_rotation_list) {
3232 UT_LIST_REMOVE(m_rotation_list, space);
3233 space->is_in_rotation_list = false;
3234 }
3235
3236 413406 UT_LIST_REMOVE(m_space_list, space);
3237
3238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413406 times.
413406 ut_a(space->magic_n == FIL_SPACE_MAGIC_N);
3239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 413406 times.
413406 ut_a(space->n_pending_flushes == 0);
3240
3241
2/2
✓ Branch 0 taken 413430 times.
✓ Branch 1 taken 413406 times.
826836 for (auto &file : space->files) {
3242
1/2
✓ Branch 0 taken 413430 times.
✗ Branch 1 not taken.
413430 file_close_to_free(&file, space);
3243 }
3244 413406 }
3245
3246 /** Free a tablespace object on which fil_space_detach() was invoked.
3247 There must not be any pending I/O's or flushes on the files.
3248 @param[in,out] space tablespace */
3249 411405 void Fil_shard::space_free_low(fil_space_t *&space) {
3250 /* Wait for fil_space_t::release_for_io(); */
3251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 411405 times.
411405 while (space->n_pending_ios) {
3252 std::this_thread::sleep_for(std::chrono::microseconds(100));
3253 }
3254
3255 #ifndef UNIV_HOTBACKUP
3256 {
3257 /* Temporary and undo tablespaces IDs are assigned from a large but
3258 fixed size pool of reserved IDs. Therefore we must ensure that a
3259 fil_space_t instance can't be dropped until all the pages that point
3260 to it are also purged from the buffer pool. */
3261
3262
4/6
✓ Branch 0 taken 184317 times.
✓ Branch 1 taken 227088 times.
✓ Branch 2 taken 184317 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 411405 times.
411405 ut_a(srv_shutdown_state.load() == SRV_SHUTDOWN_LAST_PHASE ||
3263 space->has_no_references());
3264 }
3265 #endif /* !UNIV_HOTBACKUP */
3266
3267
2/2
✓ Branch 0 taken 411429 times.
✓ Branch 1 taken 411405 times.
822834 for (auto &file : space->files) {
3268 411429 ut_d(space->size -= file.size);
3269
3270
1/2
✓ Branch 0 taken 411429 times.
✗ Branch 1 not taken.
411429 os_event_destroy(file.sync_event);
3271
3272 411429 ut::free(file.name);
3273 }
3274
3275 411405 call_destructor(&space->files);
3276
3277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 411405 times.
411405 ut_ad(space->size == 0);
3278
3279 411405 rw_lock_free(&space->latch);
3280
3281 411405 fil_space_destroy_crypt_data(&space->crypt_data);
3282
3283 411405 ut::free(space->name);
3284 411405 ut::free(space);
3285
3286 411405 space = nullptr;
3287 411405 }
3288
3289 /** Frees a space object from the tablespace memory cache.
3290 Closes a tablespaces' files but does not delete them.
3291 There must not be any pending I/O's or flushes on the files.
3292 @param[in] space_id Tablespace ID
3293 @return fil_space_t instance on success or nullptr */
3294 20 fil_space_t *Fil_shard::space_free(space_id_t space_id) {
3295 20 mutex_acquire();
3296
3297 20 fil_space_t *space = get_space_by_id(space_id);
3298
3299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (space != nullptr) {
3300 space_detach(space);
3301
3302 space_remove_from_lookup_maps(space_id);
3303 }
3304
3305 20 mutex_release();
3306
3307 20 return space;
3308 }
3309
3310 /** Frees a space object from the tablespace memory cache.
3311 Closes a tablespaces' files but does not delete them.
3312 There must not be any pending i/o's or flushes on the files.
3313 @param[in] space_id Tablespace ID
3314 @param[in] x_latched Whether the caller holds X-mode space->latch
3315 @return true if success */
3316 20 static bool fil_space_free(space_id_t space_id, bool x_latched) {
3317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 ut_ad(space_id != TRX_SYS_SPACE);
3318
3319
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 auto shard = fil_system->shard_by_id(space_id);
3320
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 auto space = shard->space_free(space_id);
3321
3322
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (space == nullptr) {
3323 20 return false;
3324 }
3325
3326 if (x_latched) {
3327 rw_lock_x_unlock(&space->latch);
3328 }
3329
3330 shard->mutex_acquire();
3331 Fil_shard::space_free_low(space);
3332 shard->mutex_release();
3333
3334 ut_a(space == nullptr);
3335
3336 return true;
3337 }
3338
3339 #ifdef UNIV_HOTBACKUP
3340 /** Frees a space object from the tablespace memory cache.
3341 Closes a tablespaces' files but does not delete them.
3342 There must not be any pending i/o's or flushes on the files.
3343 @param[in] space_id Tablespace ID
3344 @return true if success */
3345 bool meb_fil_space_free(space_id_t space_id) {
3346 return fil_space_free(space_id, false);
3347 }
3348 #endif /* UNIV_HOTBACKUP */
3349
3350 /** Create a space memory object and put it to the fil_system hash table.
3351 The tablespace name is independent from the tablespace file-name.
3352 Error messages are issued to the server log.
3353 @param[in] name Tablespace name
3354 @param[in] space_id Tablespace identifier
3355 @param[in] flags Tablespace flags
3356 @param[in] purpose Tablespace purpose
3357 @return pointer to created tablespace, to be filled in with fil_node_create()
3358 @retval nullptr on failure (such as when the same tablespace exists) */
3359 450474 fil_space_t *Fil_shard::space_create(const char *name, space_id_t space_id,
3360 uint32_t flags, fil_type_t purpose,
3361 fil_space_crypt_t *crypt_data,
3362 fil_encryption_t mode) {
3363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450474 times.
450474 ut_ad(mutex_owned());
3364
3365 /* Look for a matching tablespace. */
3366 450474 fil_space_t *space = get_space_by_name(name);
3367
3368
1/2
✓ Branch 0 taken 450474 times.
✗ Branch 1 not taken.
450474 if (space == nullptr) {
3369 450474 space = get_space_by_id(space_id);
3370 }
3371
3372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450474 times.
450474 if (space != nullptr) {
3373 std::ostringstream oss;
3374
3375 for (size_t i = 0; i < space->files.size(); ++i) {
3376 oss << "'" << space->files[i].name << "'";
3377
3378 if (i < space->files.size() - 1) {
3379 oss << ", ";
3380 }
3381 }
3382
3383 ut_ad(space->id != space_id);
3384 ib::info(ER_IB_MSG_281)
3385 << "Trying to add tablespace '" << name << "'"
3386 << " with id " << space_id << " to the tablespace"
3387 << " memory cache, but tablespace"
3388 << " '" << space->name << "'"
3389 << " already exists in the cache with space ID " << space->id
3390 << ". It maps to the following file(s): " << oss.str();
3391
3392 return nullptr;
3393 }
3394
3395 space = static_cast<fil_space_t *>(
3396 450474 ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, sizeof(*space)));
3397 /* This could be just a placement new constructor call if, only if it compiles
3398 OK on SunPro. */
3399 450474 space->initialize();
3400
3401 450474 space->id = space_id;
3402 450474 space->name = mem_strdup(name);
3403
3404 #ifndef UNIV_HOTBACKUP
3405
2/2
✓ Branch 0 taken 162487 times.
✓ Branch 1 taken 10681 times.
623642 if (fil_system->is_greater_than_max_id(space_id) && !recv_recovery_on &&
3406
4/6
✓ Branch 0 taken 173168 times.
✓ Branch 1 taken 277306 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 162487 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 450474 times.
623642 !dict_sys_t::is_reserved(space_id) &&
3407 !fsp_is_system_temporary(space_id)) {
3408 fil_system->set_maximum_space_id(space);
3409 }
3410 #endif /* !UNIV_HOTBACKUP */
3411
3412 450474 space->purpose = purpose;
3413
3414 450474 space->crypt_data = crypt_data;
3415
3416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 450474 times.
450474 ut_a(flags < std::numeric_limits<uint32_t>::max());
3417 450474 space->flags = (uint32_t)flags;
3418
3419 450474 space->magic_n = FIL_SPACE_MAGIC_N;
3420
3421 450474 space->m_encryption_metadata.m_type = Encryption::NONE;
3422 450474 space->encryption_op_in_progress = Encryption::Progress::NONE;
3423
3424 450474 rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
3425
3426 450474 space->is_corrupt = false;
3427
3428 450474 space->is_space_encrypted = false;
3429
3430 450474 space->exclude_from_rotation = false;
3431
3432 #ifndef UNIV_HOTBACKUP
3433
2/2
✓ Branch 0 taken 131572 times.
✓ Branch 1 taken 318902 times.
450474 if (space->purpose == FIL_TYPE_TEMPORARY) {
3434 131572 ut_d(space->latch.set_temp_fsp());
3435 }
3436 #endif /* !UNIV_HOTBACKUP */
3437
3438 450474 space_add(space, mode);
3439
3440 450474 return space;
3441 }
3442
3443 /** Create a space memory object and put it to the fil_system hash table.
3444 The tablespace name is independent from the tablespace file-name.
3445 Error messages are issued to the server log.
3446 @param[in] name Tablespace name
3447 @param[in] space_id Tablespace ID
3448 @param[in] flags Tablespace flags
3449 @param[in] purpose Tablespace purpose
3450 @return pointer to created tablespace, to be filled in with fil_node_create()
3451 @retval nullptr on failure (such as when the same tablespace exists) */
3452 439779 fil_space_t *fil_space_create(const char *name, space_id_t space_id,
3453 uint32_t flags, fil_type_t purpose,
3454 fil_space_crypt_t *crypt_data,
3455 fil_encryption_t mode) {
3456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 439779 times.
439779 ut_ad(fsp_flags_is_valid(flags));
3457
4/6
✓ Branch 0 taken 1308 times.
✓ Branch 1 taken 438471 times.
✓ Branch 2 taken 1308 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 439779 times.
439779 ut_ad(srv_page_size == UNIV_PAGE_SIZE_ORIG || flags != 0);
3458
3459
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 439777 times.
439779 DBUG_EXECUTE_IF("fil_space_create_failure", return nullptr;);
3460
3461 439777 fil_system->mutex_acquire_all();
3462
3463 439777 auto shard = fil_system->shard_by_id(space_id);
3464
3465 auto space =
3466 439777 shard->space_create(name, space_id, flags, purpose, crypt_data, mode);
3467
3468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 439777 times.
439777 if (space == nullptr) {
3469 /* Duplicate error. */
3470 fil_system->mutex_release_all();
3471 return nullptr;
3472 }
3473
3474 /* Cache the system tablespaces, avoid looking them up during IO. */
3475
3476
2/2
✓ Branch 0 taken 11981 times.
✓ Branch 1 taken 427796 times.
439777 if (space->id == TRX_SYS_SPACE) {
3477
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 11981 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11981 times.
11981 ut_a(fil_space_t::s_sys_space == nullptr ||
3478 fil_space_t::s_sys_space == space);
3479
3480 11981 fil_space_t::s_sys_space = space;
3481 }
3482
3483 439777 fil_system->mutex_release_all();
3484
3485 439777 return space;
3486 }
3487
3488 /** Assigns a new space id for a new single-table tablespace. This
3489 works simply by incrementing the global counter. If 4 billion ids
3490 is not enough, we may need to recycle ids.
3491 @param[out] space_id Set this to the new tablespace ID
3492 @return true if assigned, false if not */
3493 194980 bool Fil_system::assign_new_space_id(space_id_t *space_id) {
3494
1/2
✓ Branch 0 taken 194980 times.
✗ Branch 1 not taken.
194980 mutex_acquire_all();
3495
3496 194980 space_id_t id = *space_id;
3497
3498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 194980 times.
194980 if (id < m_max_assigned_id) {
3499 id = m_max_assigned_id;
3500 }
3501
3502 194980 ++id;
3503
3504 194980 space_id_t reserved_space_id = dict_sys_t::s_reserved_space_id;
3505
3506
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 194980 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
194980 if (id > (reserved_space_id / 2) && (id % 1000000UL == 0)) {
3507 ib::warn(ER_IB_MSG_282)
3508 << "You are running out of new single-table"
3509 " tablespace id's. Current counter is "
3510 << id << " and it must not exceed " << reserved_space_id
3511 << "! To reset the counter to zero you have to dump"
3512 " all your tables and recreate the whole InnoDB"
3513 " installation.";
3514 }
3515
3516 194980 bool success = !dict_sys_t::is_reserved(id);
3517
3518
1/2
✓ Branch 0 taken 194980 times.
✗ Branch 1 not taken.
194980 if (success) {
3519 194980 *space_id = m_max_assigned_id = id;
3520
3521 } else {
3522 ib::warn(ER_IB_MSG_283) << "You have run out of single-table tablespace"
3523 " id's! Current counter is "
3524 << id
3525 << ". To reset the counter to zero"
3526 " you have to dump all your tables and"
3527 " recreate the whole InnoDB installation.";
3528
3529 *space_id = SPACE_UNKNOWN;
3530 }
3531
3532
1/2
✓ Branch 0 taken 194980 times.
✗ Branch 1 not taken.
194980 mutex_release_all();
3533
3534 194980 return success;
3535 }
3536
3537 /** Assigns a new space id for a new single-table tablespace. This works
3538 simply by incrementing the global counter. If 4 billion id's is not enough,
3539 we may need to recycle id's.
3540 @param[out] space_id Set this to the new tablespace ID
3541 @return true if assigned, false if not */
3542 194980 bool fil_assign_new_space_id(space_id_t *space_id) {
3543 194980 return fil_system->assign_new_space_id(space_id);
3544 }
3545
3546 /** Open the files associated with a tablespace, make sure the size of
3547 the tablespace is read from the header page, and return a pointer to the
3548 fil_space_t that is in the memory cache associated with the given space id.
3549 @param[in] space_id Get the tablespace instance or this ID
3550 @return file_space_t pointer, nullptr if space not found */
3551 1010138248 fil_space_t *Fil_shard::space_load(space_id_t space_id) {
3552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1010141274 times.
1010138248 ut_ad(mutex_owned());
3553
3554 1010141274 fil_space_t *space = get_space_by_id(space_id);
3555
3556
4/4
✓ Branch 0 taken 421618969 times.
✓ Branch 1 taken 3481 times.
✓ Branch 2 taken 421567678 times.
✓ Branch 3 taken 51291 times.
421622450 if (space == nullptr || space->size != 0) {
3557 421571159 return space;
3558 }
3559
3560
1/2
✓ Branch 0 taken 51291 times.
✗ Branch 1 not taken.
51291 switch (space->purpose) {
3561 51291 case FIL_TYPE_IMPORT:
3562 case FIL_TYPE_TEMPORARY:
3563 case FIL_TYPE_TABLESPACE:
3564
3565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51291 times.
51291 ut_a(space_id != TRX_SYS_SPACE);
3566
3567 51291 space = get_space_by_id(space_id);
3568
3569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51291 times.
51291 if (space == nullptr) {
3570 return nullptr;
3571 }
3572
3573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51291 times.
51291 ut_a(1 == space->files.size());
3574
3575 {
3576 51291 auto file = &space->files.front();
3577
3578 /* It must be a single-table tablespace and
3579 we have not opened the file yet; the following
3580 calls will open it and update the size fields */
3581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51291 times.
51291 if (!prepare_file_for_io(file)) {
3582 /* The single-table tablespace can't be opened,
3583 because the ibd file is missing. */
3584
3585 return nullptr;
3586 }
3587
3588
1/2
✓ Branch 0 taken 51291 times.
✗ Branch 1 not taken.
51291 complete_io(file, IORequestRead);
3589 }
3590 }
3591
3592 51291 return space;
3593 }
3594
3595 /** Returns the path from the first fil_node_t found with this space ID.
3596 The caller is responsible for freeing the memory allocated here for the
3597 value returned.
3598 @param[in] space_id Tablespace ID
3599 @return own: A copy of fil_node_t::path, nullptr if space ID is zero
3600 or not found. */
3601 540634 char *fil_space_get_first_path(space_id_t space_id) {
3602 540634 auto shard = fil_system->shard_by_id(space_id);
3603
3604 540634 shard->mutex_acquire();
3605
3606 540634 fil_space_t *space = shard->space_load(space_id);
3607
3608 char *path;
3609
3610
2/2
✓ Branch 0 taken 537971 times.
✓ Branch 1 taken 2663 times.
540634 if (space != nullptr) {
3611 537971 path = mem_strdup(space->files.front().name);
3612 } else {
3613 2663 path = nullptr;
3614 }
3615
3616 540634 shard->mutex_release();
3617
3618 540634 return path;
3619 }
3620
3621 /** Returns the size of the space in pages. The tablespace must be cached
3622 in the memory cache.
3623 @param[in] space_id Tablespace ID
3624 @return space size, 0 if space not found */
3625 85930 page_no_t fil_space_get_size(space_id_t space_id) {
3626 85930 auto shard = fil_system->shard_by_id(space_id);
3627
3628 85930 shard->mutex_acquire();
3629
3630 85930 fil_space_t *space = shard->space_load(space_id);
3631
3632
2/2
✓ Branch 0 taken 85929 times.
✓ Branch 1 taken 1 times.
85930 page_no_t size = space ? space->size : 0;
3633
3634 85930 shard->mutex_release();
3635
3636 85930 return size;
3637 }
3638
3639 125488 page_no_t fil_space_get_undo_initial_size(space_id_t space_id) {
3640 125488 auto shard = fil_system->shard_by_id(space_id);
3641
3642 125488 shard->mutex_acquire();
3643
3644 125488 fil_space_t *space = shard->space_load(space_id);
3645
3646
1/2
✓ Branch 0 taken 125488 times.
✗ Branch 1 not taken.
125488 page_no_t size = space ? space->m_undo_initial : 0;
3647
3648 125488 shard->mutex_release();
3649
3650 125488 return size;
3651 }
3652
3653 48290 void fil_space_set_undo_size(space_id_t space_id, bool use_current) {
3654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48290 times.
48290 ut_ad(fsp_is_undo_tablespace(space_id));
3655
3656 48290 auto shard = fil_system->shard_by_id(space_id);
3657
3658 48290 shard->mutex_acquire();
3659
3660 48290 fil_space_t *space = shard->space_load(space_id);
3661
3662
1/2
✓ Branch 0 taken 48290 times.
✗ Branch 1 not taken.
48290 if (space != nullptr) {
3663
2/2
✓ Branch 0 taken 24935 times.
✓ Branch 1 taken 23355 times.
48290 space->m_undo_initial =
3664 23355 (use_current ? space->size : UNDO_INITIAL_SIZE_IN_PAGES);
3665 48290 space->m_undo_extend = UNDO_INITIAL_SIZE_IN_PAGES;
3666 }
3667
3668 48290 shard->mutex_release();
3669 48290 }
3670
3671 /** Returns the flags of the space. The tablespace must be cached
3672 in the memory cache.
3673 @param[in] space_id Tablespace ID for which to get the flags
3674 @return flags, ULINT_UNDEFINED if space not found */
3675 398042617 uint32_t fil_space_get_flags(space_id_t space_id) {
3676 398042617 auto shard = fil_system->shard_by_id(space_id);
3677
3678 398045351 shard->mutex_acquire();
3679
3680 1009047758 fil_space_t *space = shard->space_load(space_id);
3681
3682 uint32_t flags;
3683
3684
2/2
✓ Branch 0 taken 1009044523 times.
✓ Branch 1 taken 5551 times.
1009050074 flags = (space != nullptr) ? space->flags : UINT32_UNDEFINED;
3685
3686 1009050074 shard->mutex_release();
3687
3688 1009054609 return flags;
3689 }
3690
3691 /** Open each file of a tablespace if not already open.
3692 @param[in] space_id tablespace identifier
3693 @retval true if all file nodes were opened
3694 @retval false on failure */
3695 42893 bool Fil_shard::space_open(space_id_t space_id) {
3696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42893 times.
42893 ut_ad(mutex_owned());
3697
3698 42893 fil_space_t *space = get_space_by_id(space_id);
3699
3700
2/2
✓ Branch 0 taken 42893 times.
✓ Branch 1 taken 42893 times.
85786 for (auto &file : space->files) {
3701
5/8
✓ Branch 0 taken 36634 times.
✓ Branch 1 taken 6259 times.
✓ Branch 2 taken 36634 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36634 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 42893 times.
42893 if (!file.is_open && !open_file(&file)) {
3702 return false;
3703 }
3704 }
3705
3706 42893 return true;
3707 }
3708
3709 /** Open each file of a tablespace if not already open.
3710 @param[in] space_id Tablespace ID
3711 @retval true if all file nodes were opened
3712 @retval false on failure */
3713 42893 bool fil_space_open(space_id_t space_id) {
3714 42893 auto shard = fil_system->shard_by_id(space_id);
3715
3716 42893 shard->mutex_acquire();
3717
3718 42893 bool success = shard->space_open(space_id);
3719
3720 42893 shard->mutex_release();
3721
3722 42893 return success;
3723 }
3724
3725 /** Close each file of a tablespace if open.
3726 @param[in] space_id Tablespace ID */
3727 221380 void fil_space_close(space_id_t space_id) {
3728
2/2
✓ Branch 0 taken 10303 times.
✓ Branch 1 taken 211077 times.
221380 if (fil_system == nullptr) {
3729 10303 return;
3730 }
3731
3732 211077 auto shard = fil_system->shard_by_id(space_id);
3733
3734 211077 shard->close_file(space_id);
3735 }
3736
3737 /** Returns the page size of the space and whether it is compressed or not.
3738 The tablespace must be cached in the memory cache.
3739 @param[in] space_id Tablespace ID
3740 @param[out] found true if tablespace was found
3741 @return page size */
3742 1008587236 const page_size_t fil_space_get_page_size(space_id_t space_id, bool *found) {
3743 1008587236 const uint32_t flags = fil_space_get_flags(space_id);
3744
3745
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 648442316 times.
648442376 if (flags == UINT32_UNDEFINED) {
3746 60 *found = false;
3747 60 return univ_page_size;
3748 }
3749
3750 648442316 *found = true;
3751
3752 648442316 return page_size_t(flags);
3753 }
3754
3755 /** Initializes the tablespace memory cache.
3756 @param[in] max_n_open Maximum number of open files */
3757 12330 void fil_init(ulint max_n_open) {
3758 static_assert((1 << UNIV_PAGE_SIZE_SHIFT_MAX) == UNIV_PAGE_SIZE_MAX,
3759 "(1 << UNIV_PAGE_SIZE_SHIFT_MAX) != UNIV_PAGE_SIZE_MAX");
3760
3761 static_assert((1 << UNIV_PAGE_SIZE_SHIFT_MIN) == UNIV_PAGE_SIZE_MIN,
3762 "(1 << UNIV_PAGE_SIZE_SHIFT_MIN) != UNIV_PAGE_SIZE_MIN");
3763
3764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12330 times.
12330 ut_a(fil_system == nullptr);
3765
3766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12330 times.
12330 ut_a(max_n_open > 0);
3767
3768 12330 fil_system = ut::new_withkey<Fil_system>(UT_NEW_THIS_FILE_PSI_KEY, MAX_SHARDS,
3769 max_n_open);
3770
3771 12330 fil_space_crypt_init();
3772 12330 }
3773
3774 16 bool fil_open_files_limit_update(size_t &new_max_open_files) {
3775 16 return fil_system->set_open_files_limit(new_max_open_files);
3776 }
3777
3778 16 bool Fil_system::set_open_files_limit(size_t &new_max_open_files) {
3779 16 const auto start_time = std::chrono::steady_clock::now();
3780 {
3781 const auto current_minimum_limit_for_open_files =
3782
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 get_minimum_limit_for_open_files(m_n_files_not_belonging_in_lru);
3783
3784
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 13 times.
16 if (new_max_open_files < current_minimum_limit_for_open_files) {
3785 /* Use the same value that was used for the check, to not mislead user
3786 with other value than was used in calculations. */
3787 3 new_max_open_files = current_minimum_limit_for_open_files;
3788 3 return false;
3789 }
3790 }
3791 /* We impose our new limit to not allow new file openings to cross new limits
3792 (including non-LRU limit). */
3793
3/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
13 if (!m_open_files_limit.set_desired_limit(new_max_open_files)) {
3794 1 new_max_open_files = 0;
3795 1 return false;
3796 }
3797
3798 /* We read the m_n_files_not_belonging_in_lru again after the
3799 m_open_files_limit write is issued. */
3800 const auto current_minimum_limit_for_open_files =
3801
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 get_minimum_limit_for_open_files(m_n_files_not_belonging_in_lru);
3802
3803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (new_max_open_files < current_minimum_limit_for_open_files) {
3804 /* The limit was already exceeded while we were setting the
3805 m_open_files_limit.get_limit(). We rollback from the limit change. There is
3806 a counterpart check in the `Fil_shard::open_file` to rollback the limit
3807 reservation if this case is encountered there. */
3808 m_open_files_limit.revert_desired_limit();
3809
3810 /* Use the same value that was used for the check, to not mislead user with
3811 other value than was used in calculations. */
3812 new_max_open_files = current_minimum_limit_for_open_files;
3813 return false;
3814 }
3815
3816 12 const auto set_new_limit_timeout = std::chrono::seconds(5);
3817
3818 for (;;) {
3819 37 auto current_n_files_open = fil_n_files_open.load();
3820
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 25 times.
37 if ((size_t)new_max_open_files >= current_n_files_open) {
3821 12 break;
3822 }
3823
3/6
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25 times.
25 if (std::chrono::steady_clock::now() - start_time > set_new_limit_timeout) {
3824 /* Timeout, let's rollback the limit change and recommend a new limit. */
3825 m_open_files_limit.revert_desired_limit();
3826
3827 /* Use the same value that was used for the check, to not mislead user
3828 with other value than was used in calculations. */
3829 new_max_open_files = current_n_files_open;
3830 return false;
3831 }
3832
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 fil_system->flush_file_spaces();
3833
3834
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
25 if (fil_system->close_file_in_all_LRU()) {
3835 /* We closed some file, loop again to re-evaluate situation. */
3836 25 continue;
3837 }
3838 wait_while_ios_in_progress();
3839 25 }
3840
3841 #ifndef UNIV_HOTBACKUP
3842 /* Set the new limit in system variable. */
3843
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 innobase_set_open_files_limit(new_max_open_files);
3844
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 m_open_files_limit.commit_desired_limit();
3845 #endif
3846
3847 12 return true;
3848 }
3849
3850 /** Open all the system files.
3851 @param[in] max_n_open Maximum number of open files allowed
3852 @param[in,out] n_open Current number of open files */
3853 820284 void Fil_shard::open_system_tablespaces(size_t max_n_open, size_t *n_open) {
3854 820284 mutex_acquire();
3855
3856
2/2
✓ Branch 0 taken 12250 times.
✓ Branch 1 taken 820284 times.
832534 for (auto elem : m_spaces) {
3857 12250 auto space = elem.second;
3858
3859
3/4
✓ Branch 0 taken 12250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 307 times.
✓ Branch 3 taken 11943 times.
12250 if (Fil_system::space_belongs_in_LRU(space)) {
3860 307 continue;
3861 }
3862
3863
2/2
✓ Branch 0 taken 11963 times.
✓ Branch 1 taken 11943 times.
23906 for (auto &file : space->files) {
3864
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 11943 times.
11963 if (!file.is_open) {
3865
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (!open_file(&file)) {
3866 /* This func is called during server's startup. If some file of log
3867 or system tablespace is missing, the server can't start
3868 successfully. So we should assert for it. */
3869 ut_error;
3870 }
3871
3872 20 ++*n_open;
3873 }
3874
3875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11963 times.
11963 if (max_n_open < 10 + *n_open) {
3876 ib::warn(ER_IB_MSG_284, *n_open, max_n_open);
3877 }
3878 }
3879 }
3880
3881 820284 mutex_release();
3882 820284 }
3883
3884 /** Opens all system tablespace data files in all shards. */
3885 12063 void Fil_system::open_all_system_tablespaces() {
3886 12063 size_t n_open = 0;
3887
3888
2/2
✓ Branch 0 taken 820284 times.
✓ Branch 1 taken 12063 times.
832347 for (auto shard : m_shards) {
3889
1/2
✓ Branch 0 taken 820284 times.
✗ Branch 1 not taken.
820284 shard->open_system_tablespaces(get_open_files_limit(), &n_open);
3890 }
3891 12063 }
3892
3893 /** Opens all system tablespace data files. They stay open until the
3894 database server shutdown. This should be called at a server startup
3895 after the space objects for the log and the system tablespace have
3896 been created. The purpose of this operation is to make sure we never
3897 run out of file descriptors if we need to read from the insert buffer
3898 or to write to the log. */
3899 12063 void fil_open_system_tablespace_files() {
3900 12063 fil_system->open_all_system_tablespaces();
3901 12063 }
3902
3903 #ifndef UNIV_HOTBACKUP
3904 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
3905 2954 static void fil_validate_space_reference_count(
3906 fil_space_t *space, Space_References &buffer_pool_references) {
3907
1/2
✓ Branch 0 taken 2954 times.
✗ Branch 1 not taken.
2954 const auto space_reference_count = space->get_reference_count();
3908
3909
2/4
✓ Branch 0 taken 2954 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2954 times.
2954 if (space_reference_count != buffer_pool_references[space]) {
3910 ib::error() << "Space id=" << space->id << " reference count is "
3911 << space_reference_count
3912 << ", while references count found in buffer pool is "
3913 << buffer_pool_references[space] << ". fast_shutdown is "
3914 << srv_fast_shutdown;
3915 }
3916 2954 }
3917
3918 29852 void Fil_shard::validate_space_reference_count(
3919 Space_References &buffer_pool_references) {
3920
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29852 times.
29852 ut_ad(!mutex_owned());
3921
3922 29852 mutex_acquire();
3923
3924
2/2
✓ Branch 0 taken 2861 times.
✓ Branch 1 taken 29852 times.
32713 for (auto &e : m_spaces) {
3925
1/2
✓ Branch 0 taken 2861 times.
✗ Branch 1 not taken.
2861 fil_validate_space_reference_count(e.second, buffer_pool_references);
3926 }
3927
3928
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 29852 times.
29945 for (auto &e : m_deleted_spaces) {
3929
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 fil_validate_space_reference_count(e.second, buffer_pool_references);
3930 }
3931
3932 29852 mutex_release();
3933 29852 }
3934 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
3935 #endif /* !UNIV_HOTBACKUP */
3936
3937 723452 void Fil_shard::close_all_files() {
3938
2/4
✓ Branch 0 taken 723452 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 723452 times.
723452 ut_ad(mutex_owned());
3939
3940 /* Iterates over a specified container of pair */
3941 2893808 auto iterate_all_spaces_files = [this](auto &spaces, auto preprocess_space,
3942 173072 auto postprocess_space) {
3943
2/2
✓ Branch 0 taken 227088 times.
✓ Branch 1 taken 1446904 times.
3347984 for (auto &e : spaces) {
3944 454176 auto &space = e.second;
3945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227088 times.
454176 if (space == nullptr) {
3946 continue;
3947 }
3948
3949
1/2
✓ Branch 0 taken 227088 times.
✗ Branch 1 not taken.
454176 preprocess_space(space);
3950
3951
2/2
✓ Branch 0 taken 227112 times.
✓ Branch 1 taken 227088 times.
908400 for (auto &file : space->files) {
3952
5/8
✓ Branch 0 taken 86536 times.
✓ Branch 1 taken 140576 times.
✓ Branch 2 taken 86536 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 86536 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 227112 times.
454224 if (file.is_open && !file.can_be_closed()) {
3953 mutex_release();
3954 std::this_thread::sleep_for(std::chrono::milliseconds{1});
3955 mutex_acquire();
3956 /* Files or spaces could have changed when we did not hold the
3957 mutex, restart the loop. */
3958 return false;
3959 }
3960
2/2
✓ Branch 0 taken 86536 times.
✓ Branch 1 taken 140576 times.
454224 if (file.is_open) {
3961
1/2
✓ Branch 0 taken 86536 times.
✗ Branch 1 not taken.
173072 close_file(&file);
3962 }
3963 }
3964
3965
1/2
✓ Branch 0 taken 215860 times.
✗ Branch 1 not taken.
454176 postprocess_space(space);
3966
3967
1/2
✓ Branch 0 taken 227088 times.
✗ Branch 1 not taken.
454176 space_free_low(space);
3968
3969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227088 times.
454176 ut_a(space == nullptr);
3970 }
3971 2893808 return true;
3972 723452 };
3973
3974 for (;;) {
3975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 723452 times.
723452 if (!iterate_all_spaces_files(
3976
1/2
✓ Branch 0 taken 723452 times.
✗ Branch 1 not taken.
723452 m_spaces,
3977 215860 [](auto space) {
3978
6/8
✓ Branch 0 taken 205557 times.
✓ Branch 1 taken 10303 times.
✓ Branch 2 taken 91784 times.
✓ Branch 3 taken 113773 times.
✓ Branch 4 taken 91784 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 215860 times.
215860 ut_a(space->id == TRX_SYS_SPACE ||
3979 space->purpose == FIL_TYPE_TEMPORARY ||
3980 space->files.size() == 1);
3981 215860 },
3982 215860 [this](auto space) { space_detach(space); })) {
3983 continue;
3984 }
3985
3986 723452 m_spaces.clear();
3987
3988 #ifndef UNIV_HOTBACKUP
3989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 723452 times.
723452 if (!iterate_all_spaces_files(
3990
1/2
✓ Branch 0 taken 723452 times.
✗ Branch 1 not taken.
723452 m_deleted_spaces,
3991 11228 [](auto space) {
3992
3/6
✓ Branch 0 taken 11228 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11228 times.
11228 ut_a(space->id != TRX_SYS_SPACE &&
3993 space->id != dict_sys_t::s_dict_space_id);
3994
3995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11228 times.
11228 ut_a(space->files.size() <= 1);
3996 11228 },
3997 11228 [](auto) {})) {
3998 continue;
3999 }
4000
4001 723452 m_deleted_spaces.clear();
4002 #endif /* !UNIV_HOTBACKUP */
4003 723452 break;
4004 }
4005 723452 }
4006
4007 /** Close all open files. */
4008 10639 void Fil_system::close_all_files() {
4009 #ifndef UNIV_HOTBACKUP
4010 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
4011 10639 bool should_validate_space_reference_count = srv_fast_shutdown == 0;
4012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10639 times.
10639 DBUG_EXECUTE_IF("buf_disable_space_reference_count_check",
4013 should_validate_space_reference_count = false;);
4014
4015
2/2
✓ Branch 0 taken 439 times.
✓ Branch 1 taken 10200 times.
10639 if (should_validate_space_reference_count) {
4016
1/2
✓ Branch 0 taken 439 times.
✗ Branch 1 not taken.
439 auto buffer_pool_references = buf_LRU_count_space_references();
4017
2/2
✓ Branch 0 taken 29852 times.
✓ Branch 1 taken 439 times.
30291 for (auto shard : m_shards) {
4018
1/2
✓ Branch 0 taken 29852 times.
✗ Branch 1 not taken.
29852 shard->validate_space_reference_count(buffer_pool_references);
4019 }
4020 439 }
4021 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
4022 #endif /* !UNIV_HOTBACKUP */
4023
4024
2/2
✓ Branch 0 taken 723452 times.
✓ Branch 1 taken 10639 times.
734091 for (auto shard : m_shards) {
4025
1/2
✓ Branch 0 taken 723452 times.
✗ Branch 1 not taken.
723452 shard->mutex_acquire();
4026
4027
1/2
✓ Branch 0 taken 723452 times.
✗ Branch 1 not taken.
723452 shard->close_all_files();
4028
4029
1/2
✓ Branch 0 taken 723452 times.
✗ Branch 1 not taken.
723452 shard->mutex_release();
4030 }
4031
4032 #ifndef UNIV_HOTBACKUP
4033 /* Revert to old names if downgrading after upgrade failure. */
4034
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 10612 times.
10639 if (srv_downgrade_partition_files) {
4035 27 rename_partition_files(true);
4036 }
4037
4038 10639 clear_old_files();
4039 #endif /* !UNIV_HOTBACKUP */
4040 10639 }
4041
4042 /** Closes all open files. There must not be any pending i/o's or not flushed
4043 modifications in the files. */
4044 10639 void fil_close_all_files() {
4045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10639 times.
10639 if (!fil_system) return;
4046
4047 10639 fil_system->close_all_files();
4048 }
4049
4050 /** Iterate through all persistent tablespace files (FIL_TYPE_TABLESPACE)
4051 returning the nodes via callback function cbk.
4052 @param[in] f Callback
4053 @return any error returned by the callback function. */
4054 58820 dberr_t Fil_shard::iterate(Fil_iterator::Function &f) {
4055 58820 mutex_acquire();
4056
4057
2/2
✓ Branch 0 taken 21564 times.
✓ Branch 1 taken 58820 times.
80384 for (auto &elem : m_spaces) {
4058 21564 auto space = elem.second;
4059
4060
2/2
✓ Branch 0 taken 9515 times.
✓ Branch 1 taken 12049 times.
21564 if (space->purpose != FIL_TYPE_TABLESPACE) {
4061 9515 continue;
4062 }
4063
4064
2/2
✓ Branch 0 taken 12061 times.
✓ Branch 1 taken 12049 times.
24110 for (auto &file : space->files) {
4065 /* Note: The callback can release the mutex. */
4066
4067
1/2
✓ Branch 0 taken 12061 times.
✗ Branch 1 not taken.
12061 dberr_t err = f(&file);
4068
4069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12061 times.
12061 if (err != DB_SUCCESS) {
4070 mutex_release();
4071
4072 return err;
4073 }
4074 }
4075 }
4076
4077 58820 mutex_release();
4078
4079 58820 return DB_SUCCESS;
4080 }
4081
4082 865 dberr_t Fil_system::iterate(Fil_iterator::Function &f) {
4083
2/2
✓ Branch 0 taken 58820 times.
✓ Branch 1 taken 865 times.
59685 for (auto shard : m_shards) {
4084
1/2
✓ Branch 0 taken 58820 times.
✗ Branch 1 not taken.
58820 dberr_t err = shard->iterate(f);
4085
4086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58820 times.
58820 if (err != DB_SUCCESS) {
4087 return err;
4088 }
4089 }
4090
4091 865 return DB_SUCCESS;
4092 }
4093
4094 865 dberr_t Fil_iterator::iterate(Function &&f) { return fil_system->iterate(f); }
4095
4096 /** Sets the max tablespace id counter if the given number is bigger than the
4097 previous value.
4098 @param[in] max_id Maximum known tablespace ID */
4099 35334 void fil_set_max_space_id_if_bigger(space_id_t max_id) {
4100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35334 times.
35334 if (dict_sys_t::is_reserved(max_id)) {
4101 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_285, ulong{max_id});
4102 }
4103
4104 35334 fil_system->update_maximum_space_id(max_id);
4105 35334 }
4106
4107 /** Write the flushed LSN to the page header of the first page in the
4108 system tablespace.
4109 @param[in] lsn Flushed LSN
4110 @return DB_SUCCESS or error number */
4111 10811 dberr_t fil_write_flushed_lsn(lsn_t lsn) {
4112 dberr_t err;
4113
4114 auto buf =
4115 10811 static_cast<byte *>(ut::aligned_alloc(UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
4116
4117 10811 const page_id_t page_id(TRX_SYS_SPACE, 0);
4118
4119
2/4
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10811 times.
✗ Branch 3 not taken.
10811 err = fil_read(page_id, univ_page_size, 0, univ_page_size.physical(), buf);
4120
4121
1/2
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
10811 if (err == DB_SUCCESS) {
4122
1/2
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
10811 mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);
4123
4124
2/4
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10811 times.
✗ Branch 3 not taken.
10811 err = fil_write(page_id, univ_page_size, 0, univ_page_size.physical(), buf);
4125
4126
1/2
✓ Branch 0 taken 10811 times.
✗ Branch 1 not taken.
10811 fil_system->flush_file_spaces();
4127 }
4128
4129 10811 ut::aligned_free(buf);
4130
4131 10811 return err;
4132 }
4133
4134 /** Acquire a tablespace when it could be dropped concurrently.
4135 Used by background threads that do not necessarily hold proper locks
4136 for concurrency control.
4137 @param[in] space_id Tablespace ID
4138 @param[in] silent Whether to silently ignore missing tablespaces
4139 @return the tablespace, or nullptr if missing or being deleted */
4140 31217712 fil_space_t *Fil_system::space_acquire(space_id_t space_id, bool silent) {
4141 31217712 auto shard = fil_system->shard_by_id(space_id);
4142
4143 31218426 shard->mutex_acquire();
4144
4145 31218957 fil_space_t *space = shard->get_space_by_id(space_id);
4146
4147
2/2
✓ Branch 0 taken 21053 times.
✓ Branch 1 taken 31197904 times.
31218957 if (space == nullptr) {
4148
6/6
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 20986 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 58 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 21044 times.
21053 if (!silent && m_ACCESSING_NONEXISTINC_SPACE_throttler.apply()) {
4149
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 ib::warn(ER_IB_WARN_ACCESSING_NONEXISTINC_SPACE, ulong{space_id});
4150 }
4151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31197896 times.
31197904 } else if (!shard->space_acquire(space)) {
4152 space = nullptr;
4153 }
4154
4155 31218949 shard->mutex_release();
4156
4157 31218965 return space;
4158 }
4159
4160 31197874 inline bool Fil_shard::space_acquire(fil_space_t *space) {
4161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31197904 times.
31197874 ut_ad(mutex_owned());
4162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31197907 times.
31197904 ut_ad(space != nullptr);
4163
4164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31197907 times.
31197907 if (space->stop_new_ops) {
4165 return false;
4166 }
4167
4168 31197907 ++space->n_pending_ops;
4169
4170 31197907 return true;
4171 }
4172
4173 /** Acquire a tablespace when it could be dropped concurrently.
4174 Used by background threads that do not necessarily hold proper locks
4175 for concurrency control.
4176 @param[in] space_id Tablespace ID
4177 @return the tablespace, or nullptr if missing or being deleted */
4178 1182894 fil_space_t *fil_space_acquire(space_id_t space_id) {
4179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1182894 times.
1182894 if (!fil_system) return nullptr;
4180 1182894 return fil_system->space_acquire(space_id, false);
4181 }
4182
4183 /** Acquire a tablespace that may not exist.
4184 Used by background threads that do not necessarily hold proper locks
4185 for concurrency control.
4186 @param[in] space_id Tablespace ID
4187 @return the tablespace, or nullptr if missing or being deleted */
4188 30034770 fil_space_t *fil_space_acquire_silent(space_id_t space_id) {
4189 30034770 return fil_system->space_acquire(space_id, true);
4190 }
4191
4192 /** Release a tablespace acquired with fil_space_acquire().
4193 @param[in,out] space Tablespace to release */
4194 31197841 void fil_space_release(fil_space_t *space) {
4195 31197841 auto shard = fil_system->shard_by_id(space->id);
4196
4197 31197905 shard->mutex_acquire();
4198 31197907 shard->space_release(space);
4199 31197902 shard->mutex_release();
4200 31197912 }
4201
4202 /** Release a tablespace acquired with Fil_shard::space_acquire().
4203 @param[in,out] space tablespace to release */
4204 31197897 void Fil_shard::space_release(fil_space_t *space) {
4205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31197907 times.
31197897 ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
4206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31197903 times.
31197907 ut_ad(space->n_pending_ops > 0);
4207
4208 31197903 --space->n_pending_ops;
4209 31197903 }
4210
4211 /** Acquire a tablespace for reading or writing a block,
4212 when it could be dropped concurrently.
4213 @param[in] id tablespace ID
4214 @return the tablespace
4215 @retval NULL if missing */
4216 55881545 fil_space_t *fil_space_acquire_for_io(space_id_t space_id) {
4217 55881545 auto shard = fil_system->shard_by_id(space_id);
4218
4219 55883093 shard->mutex_acquire();
4220
4221 55883715 fil_space_t *space = shard->get_space_by_id(space_id);
4222
4223
2/2
✓ Branch 0 taken 55883721 times.
✓ Branch 1 taken 8 times.
55883729 if (space) {
4224 55883721 space->n_pending_ios++;
4225 }
4226
4227 55883729 shard->mutex_release();
4228
4229 55883748 return (space);
4230 }
4231
4232 /** Acquire a tablespace for reading or writing a block,
4233 when it could be dropped concurrently.
4234 @param[in] id tablespace ID
4235 @return the tablespace
4236 @retval NULL if missing */
4237 289560 fil_space_t *fil_space_acquire_for_io_with_load(space_id_t space_id) {
4238 289560 auto shard = fil_system->shard_by_id(space_id);
4239
4240 289560 shard->mutex_acquire();
4241
4242 289560 fil_space_t *space = shard->space_load(space_id);
4243
4244
1/2
✓ Branch 0 taken 289560 times.
✗ Branch 1 not taken.
289560 if (space) {
4245 289560 space->n_pending_ios++;
4246 }
4247
4248 289560 shard->mutex_release();
4249
4250 289560 return (space);
4251 }
4252
4253 /** Release a tablespace acquired with fil_space_acquire_for_io().
4254 @param[in,out] space tablespace to release */
4255 56172240 void fil_space_release_for_io(fil_space_t *space) {
4256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56172781 times.
56172240 ut_ad(space);
4257 56172781 auto shard = fil_system->shard_by_id(space->id);
4258
4259 56172883 shard->mutex_acquire();
4260
4261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56173257 times.
56173228 ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
4262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56173270 times.
56173257 ut_ad(space->n_pending_ios > 0);
4263
4264 56173270 --space->n_pending_ios;
4265
4266 56173270 shard->mutex_release();
4267 56173276 }
4268
4269 3097 fil_space_t *fil_space_get_next_in_shard(fil_space_t *space, Fil_shard *shard) {
4270
2/2
✓ Branch 0 taken 2729 times.
✓ Branch 1 taken 368 times.
3097 space = (space == nullptr) ? UT_LIST_GET_FIRST(shard->m_space_list)
4271 : UT_LIST_GET_NEXT(space_list, space);
4272 /* Skip spaces that are being created by
4273 fil_ibd_create(), or dropped, or !tablespace. */
4274
7/8
✓ Branch 0 taken 814 times.
✓ Branch 1 taken 2725 times.
✓ Branch 2 taken 814 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 812 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 442 times.
✓ Branch 7 taken 3097 times.
4351 while (space != nullptr && (space->files.empty() || space->is_stopping() ||
4275
2/2
✓ Branch 0 taken 440 times.
✓ Branch 1 taken 372 times.
812 space->purpose != FIL_TYPE_TABLESPACE)) {
4276 442 space = UT_LIST_GET_NEXT(space_list, space);
4277 }
4278 3097 return space;
4279 }
4280
4281 /**
4282 Remove space from key rotation list if there are no more
4283 pending operations.
4284 @param[in] space Tablespace */
4285 static void fil_space_remove_from_keyrotation(Fil_shard *shard,
4286 fil_space_t *space) {
4287 ut_ad(shard->mutex_owned());
4288 ut_ad(space);
4289
4290 if (space->n_pending_ops == 0 && space->is_in_rotation_list) {
4291 space->is_in_rotation_list = false;
4292 ut_a(UT_LIST_GET_LEN(shard->m_rotation_list) > 0);
4293 UT_LIST_REMOVE(shard->m_rotation_list, space);
4294 }
4295 }
4296
4297 fil_space_t *fil_space_get_next_in_shards_rotation_list(fil_space_t *space,
4298 Fil_shard *shard) {
4299 if (space == nullptr) {
4300 space = UT_LIST_GET_FIRST(shard->m_rotation_list);
4301 } else {
4302 fil_space_t *prev_space = space;
4303 space = UT_LIST_GET_NEXT(rotation_list, prev_space);
4304 fil_space_remove_from_keyrotation(shard, prev_space);
4305 }
4306 /* Skip spaces that are being created by
4307 fil_ibd_create(), or dropped, or !tablespace. */
4308 while (space != nullptr && (space->files.empty() || space->is_stopping() ||
4309 space->purpose != FIL_TYPE_TABLESPACE)) {
4310 fil_space_t *prev_space = space;
4311 space = UT_LIST_GET_NEXT(rotation_list, prev_space);
4312 fil_space_remove_from_keyrotation(shard, prev_space);
4313 }
4314 return space;
4315 }
4316
4317 /** Return the next fil_space_t.
4318 Once started, the caller must keep calling this until it returns NULL.
4319 fil_space_acquire() and fil_space_t::release() are invoked here which
4320 blocks a concurrent operation from dropping the tablespace.
4321 @param[in] prev_space Pointer to the previous fil_space_t.
4322 If NULL, use the first fil_space_t on fil_system.space_list.
4323 @return pointer to the next fil_space_t.
4324 @retval NULL if this was the last*/
4325 412 fil_space_t *fil_space_next(
4326 fil_space_t *prev_space) // TODO: It should be a part of Fil_system
4327 {
4328 412 fil_space_t *space = prev_space;
4329
4330
1/2
✓ Branch 0 taken 412 times.
✗ Branch 1 not taken.
412 mutex_enter(&fil_crypt_list_mutex);
4331
4332 412 Fil_shard *shard = nullptr;
4333 412 uint shard_index = 0;
4334
4335
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 368 times.
412 if (prev_space == nullptr) {
4336
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 shard = fil_system->shard_by_index(shard_index);
4337
4338
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 shard->mutex_acquire();
4339
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 space = fil_space_get_next_in_shard(prev_space, shard);
4340 }
4341
4342
2/2
✓ Branch 0 taken 368 times.
✓ Branch 1 taken 44 times.
412 if (prev_space != nullptr) {
4343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 368 times.
368 ut_ad(space->n_pending_ops >
4344 0); // we are sure that space exists as space
4345 // with n_pending_ops > 0 cannot be removed
4346
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 shard = fil_system->shard_by_id(space->id, &shard_index);
4347
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 shard->mutex_acquire();
4348
4349 /* Move on to the next fil_space_t */
4350 368 space->n_pending_ops--;
4351
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 space = fil_space_get_next_in_shard(space, shard);
4352 }
4353
4354
6/6
✓ Branch 0 taken 2725 times.
✓ Branch 1 taken 372 times.
✓ Branch 2 taken 2685 times.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 2685 times.
✓ Branch 5 taken 412 times.
5822 while (space == nullptr &&
4355 2725 (++shard_index < fil_system->get_number_of_shards())) {
4356
1/2
✓ Branch 0 taken 2685 times.
✗ Branch 1 not taken.
2685 shard->mutex_release();
4357
1/2
✓ Branch 0 taken 2685 times.
✗ Branch 1 not taken.
2685 shard = fil_system->shard_by_index(shard_index);
4358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2685 times.
2685 ut_ad(shard != nullptr);
4359
1/2
✓ Branch 0 taken 2685 times.
✗ Branch 1 not taken.
2685 shard->mutex_acquire();
4360
1/2
✓ Branch 0 taken 2685 times.
✗ Branch 1 not taken.
2685 space = fil_space_get_next_in_shard(space, shard);
4361 }
4362
4363
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 40 times.
412 if (space != nullptr) {
4364 372 space->n_pending_ops++;
4365 }
4366
4367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 412 times.
412 ut_ad(shard != nullptr);
4368
1/2
✓ Branch 0 taken 412 times.
✗ Branch 1 not taken.
412 shard->mutex_release();
4369
1/2
✓ Branch 0 taken 412 times.
✗ Branch 1 not taken.
412 mutex_exit(&fil_crypt_list_mutex);
4370
4371 412 return (space);
4372 }
4373
4374 /** Return the next fil_space_t from key rotation list.
4375 Once started, the caller must keep calling this until it returns NULL.
4376 fil_space_acquire() and fil_space_release() are invoked here which
4377 blocks a concurrent operation from dropping the tablespace.
4378 @param[in] prev_space Pointer to the previous fil_space_t.
4379 If NULL, use the first fil_space_t on fil_system->space_list.
4380 @return pointer to the next fil_space_t.
4381 @retval NULL if this was the last*/
4382 fil_space_t *fil_space_keyrotate_next(
4383 fil_space_t *prev_space) { // TODO: To powinno być częścią Fil_system
4384
4385 fil_space_t *space = prev_space;
4386 mutex_enter(&fil_crypt_list_mutex);
4387
4388 Fil_shard *shard = nullptr;
4389 uint shard_index = 0;
4390
4391 if (prev_space == nullptr) {
4392 shard = fil_system->shard_by_index(shard_index);
4393
4394 shard->mutex_acquire();
4395 space = fil_space_get_next_in_shards_rotation_list(prev_space, shard);
4396 }
4397
4398 if (prev_space != NULL) {
4399 ut_ad(space->n_pending_ops >
4400 0); // we are sure that space exists as space
4401 // with n_pending_ops > 0 cannot be removed
4402 uint shard_index = 0;
4403 shard = fil_system->shard_by_id(space->id, &shard_index);
4404 shard->mutex_acquire();
4405 /* Move on to the next fil_space_t */
4406 space->n_pending_ops--;
4407 space = fil_space_get_next_in_shards_rotation_list(prev_space, shard);
4408 }
4409
4410 while (space == nullptr &&
4411 (++shard_index < fil_system->get_number_of_shards())) {
4412 shard->mutex_release();
4413 shard = fil_system->shard_by_index(shard_index);
4414 ut_ad(shard != nullptr);
4415 shard->mutex_acquire();
4416 space = fil_space_get_next_in_shards_rotation_list(space, shard);
4417 }
4418
4419 if (space != nullptr) {
4420 space->n_pending_ops++;
4421 }
4422
4423 ut_ad(shard != nullptr);
4424 shard->mutex_release();
4425 mutex_exit(&fil_crypt_list_mutex);
4426
4427 return space;
4428 }
4429
4430 /** Check for pending operations.
4431 @param[in] space tablespace
4432 @param[in] count number of attempts so far
4433 @return 0 if no pending operations else count + 1. */
4434 286628 ulint Fil_shard::space_check_pending_operations(fil_space_t *space,
4435 ulint count) const {
4436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 286628 times.
286628 ut_ad(mutex_owned());
4437
4438
4/4
✓ Branch 0 taken 286414 times.
✓ Branch 1 taken 214 times.
✓ Branch 2 taken 826 times.
✓ Branch 3 taken 285588 times.
286628 if (space != nullptr && space->n_pending_ops > 0) {
4439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 if (count > 5000) {
4440 ib::warn(ER_IB_MSG_287, space->name, ulong{space->n_pending_ops});
4441 }
4442
4443 826 return count + 1;
4444 }
4445
4446 285802 return 0;
4447 }
4448
4449 /** Check for pending IO.
4450 @param[in] space Tablespace to check
4451 @param[in] file File in space list
4452 @param[in] count number of attempts so far
4453 @return 0 if no pending else count + 1. */
4454 285885 ulint Fil_shard::check_pending_io(const fil_space_t *space,
4455 const fil_node_t &file, ulint count) const {
4456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285885 times.
285885 ut_ad(mutex_owned());
4457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285885 times.
285885 ut_a(space->n_pending_ops == 0);
4458
4459
5/8
✓ Branch 0 taken 285885 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197809 times.
✓ Branch 3 taken 88076 times.
✓ Branch 4 taken 197809 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 285885 times.
285885 ut_a(space->id == TRX_SYS_SPACE || space->purpose == FIL_TYPE_TEMPORARY ||
4460 space->files.size() == 1);
4461
4462
4/4
✓ Branch 0 taken 285661 times.
✓ Branch 1 taken 224 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 285588 times.
285885 if (space->n_pending_flushes > 0 || file.n_pending_ios > 0) {
4463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 297 times.
297 if (count > 1000) {
4464 ib::warn(ER_IB_MSG_288, space->name, ulong{space->n_pending_flushes},
4465 size_t{file.n_pending_ios});
4466 }
4467
4468 297 return count + 1;
4469 }
4470
4471 285588 return 0;
4472 }
4473
4474 285802 dberr_t Fil_shard::wait_for_pending_operations(space_id_t space_id,
4475 fil_space_t *&space,
4476 char **path) const {
4477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285802 times.
285802 ut_ad(!fsp_is_system_tablespace(space_id));
4478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285802 times.
285802 ut_ad(!fsp_is_global_temporary(space_id));
4479
4480 285802 space = nullptr;
4481
4482 285802 mutex_acquire();
4483
4484 285802 fil_space_t *sp = get_space_by_id(space_id);
4485
4486
2/2
✓ Branch 0 taken 285588 times.
✓ Branch 1 taken 214 times.
285802 if (sp != nullptr) {
4487 285588 sp->stop_new_ops = true;
4488
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 285575 times.
285588 if (sp->crypt_data) {
4489 13 sp->n_pending_ops++;
4490 13 mutex_release();
4491 13 fil_space_crypt_close_tablespace(sp);
4492 13 mutex_acquire();
4493
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 ut_ad(sp->n_pending_ops > 0);
4494 13 sp->n_pending_ops--;
4495 }
4496 }
4497
4498 /* Check for pending operations. */
4499
4500 285802 ulint count = 0;
4501
4502 do {
4503 286628 sp = get_space_by_id(space_id);
4504
4505 286628 count = space_check_pending_operations(sp, count);
4506
4507 286628 mutex_release();
4508
4509
2/2
✓ Branch 0 taken 826 times.
✓ Branch 1 taken 285802 times.
286628 if (count > 0) {
4510
1/2
✓ Branch 0 taken 826 times.
✗ Branch 1 not taken.
826 std::this_thread::sleep_for(std::chrono::milliseconds(20));
4511 }
4512
4513 286628 mutex_acquire();
4514
4515
2/2
✓ Branch 0 taken 826 times.
✓ Branch 1 taken 285802 times.
286628 } while (count > 0);
4516
4517 /* Check for pending IO. */
4518
4519 285802 *path = nullptr;
4520
4521 do {
4522 286099 sp = get_space_by_id(space_id);
4523
4524
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 285885 times.
286099 if (sp == nullptr) {
4525 214 mutex_release();
4526
4527 214 return DB_TABLESPACE_NOT_FOUND;
4528 }
4529
4530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285885 times.
285885 ut_a(sp->files.size() == 1);
4531 285885 const fil_node_t &file = sp->files.front();
4532
4533 285885 count = check_pending_io(sp, file, count);
4534
4535
2/2
✓ Branch 0 taken 285588 times.
✓ Branch 1 taken 297 times.
285885 if (count == 0) {
4536 285588 *path = mem_strdup(file.name);
4537 }
4538
4539 285885 mutex_release();
4540
4541
2/2
✓ Branch 0 taken 285588 times.
✓ Branch 1 taken 297 times.
285885 if (count == 0) {
4542 285588 break;
4543 }
4544
4545
1/2
✓ Branch 0 taken 297 times.
✗ Branch 1 not taken.
297 std::this_thread::sleep_for(std::chrono::milliseconds(20));
4546 297 mutex_acquire();
4547
4548
1/2
✓ Branch 0 taken 297 times.
✗ Branch 1 not taken.
297 } while (count > 0);
4549
4550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285588 times.
285588 ut_ad(sp != nullptr);
4551
4552 285588 space = sp;
4553
4554 285588 return DB_SUCCESS;
4555 }
4556
4557 3500 std::string Fil_path::get_existing_path(const std::string &path,
4558 std::string &ghost) {
4559 3500 std::string existing_path{path};
4560
4561 /* This is only called for non-existing paths. */
4562
3/4
✓ Branch 0 taken 8091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4591 times.
✓ Branch 3 taken 3500 times.
8091 while (!os_file_exists(existing_path.c_str())) {
4563 /* Some part of this path does not exist.
4564 If the last char is a separator, strip it off. */
4565
1/2
✓ Branch 0 taken 4591 times.
✗ Branch 1 not taken.
4591 trim_separator(existing_path);
4566
4567 4591 auto sep = existing_path.find_last_of(SEPARATOR);
4568
2/2
✓ Branch 0 taken 1288 times.
✓ Branch 1 taken 3303 times.
4591 if (sep == std::string::npos) {
4569 /* If no separator is found, it must be relative to the current dir. */
4570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1288 times.
1288 if (existing_path == ".") {
4571 /* This probably cannot happen, but break here to ensure that the
4572 loop always has a way out. */
4573 break;
4574 }
4575
1/2
✓ Branch 0 taken 1288 times.
✗ Branch 1 not taken.
1288 ghost.assign(path);
4576
1/2
✓ Branch 0 taken 1288 times.
✗ Branch 1 not taken.
1288 existing_path.assign(".");
4577
1/2
✓ Branch 0 taken 1288 times.
✗ Branch 1 not taken.
1288 existing_path.push_back(OS_SEPARATOR);
4578 } else {
4579
1/2
✓ Branch 0 taken 3303 times.
✗ Branch 1 not taken.
3303 ghost.assign(path.substr(sep + 1, path.length()));
4580
1/2
✓ Branch 0 taken 3303 times.
✗ Branch 1 not taken.
3303 existing_path.resize(sep + 1);
4581 }
4582 }
4583
4584 3500 return existing_path;
4585 }
4586
4587 1059908 std::string Fil_path::get_real_path(const std::string &path, bool force) {
4588 bool path_exists;
4589 os_file_type_t path_type;
4590 char abspath[OS_FILE_MAX_PATH];
4591
1/2
✓ Branch 0 taken 1059908 times.
✗ Branch 1 not taken.
1059908 std::string in_path{path};
4592 1059908 std::string real_path;
4593
4594
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1059907 times.
1059908 if (path.empty()) {
4595
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 return std::string("");
4596 }
4597
4598 /* We do not need a separator at the end in order to determine what
4599 kind of object it is. So take it off. If it is there and the last
4600 part is actually a file, the correct real path will be returned. */
4601
6/6
✓ Branch 0 taken 1035377 times.
✓ Branch 1 taken 24530 times.
✓ Branch 2 taken 296206 times.
✓ Branch 3 taken 739171 times.
✓ Branch 4 taken 296206 times.
✓ Branch 5 taken 763701 times.
1059907 if (in_path.length() > 1 && is_separator(in_path.back())) {
4602
1/2
✓ Branch 0 taken 296206 times.
✗ Branch 1 not taken.
296206 trim_separator(in_path);
4603 }
4604
4605 /* Before we make an absolute path, check if this path exists,
4606 and if so, what type it is. */
4607
1/2
✓ Branch 0 taken 1059907 times.
✗ Branch 1 not taken.
1059907 os_file_status(in_path.c_str(), &path_exists, &path_type);
4608
4609
1/2
✓ Branch 0 taken 1059907 times.
✗ Branch 1 not taken.
1059907 int ret = my_realpath(abspath, in_path.c_str(), MYF(0));
4610
4611
2/2
✓ Branch 0 taken 1056461 times.
✓ Branch 1 taken 3446 times.
1059907 if (ret == 0) {
4612
1/2
✓ Branch 0 taken 1056461 times.
✗ Branch 1 not taken.
1056461 real_path.assign(abspath);
4613 } else {
4614 /* This often happens on non-Windows platforms when the path does not
4615 fully exist yet. */
4616
4617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3446 times.
3446 if (path_exists) {
4618 /* my_realpath() failed for some reason other than the path does not
4619 exist. */
4620 if (force) {
4621 /* Use the given path and make it comparable. */
4622 real_path.assign(in_path);
4623 } else {
4624 /* Return null and make a note of it. Another attempt will be made
4625 later when Fil_path::get_real_path() is called with force=true. */
4626 ib::info(ER_IB_MSG_289) << "my_realpath('" << path
4627 << "') failed for path type " << path_type;
4628 return (std::string(""));
4629 }
4630 } else {
4631 /* The path does not exist. Try my_realpath() again with the
4632 existing portion of the path. */
4633 3446 std::string ghost;
4634
1/2
✓ Branch 0 taken 3446 times.
✗ Branch 1 not taken.
3446 std::string dir = get_existing_path(in_path, ghost);
4635
4636
1/2
✓ Branch 0 taken 3446 times.
✗ Branch 1 not taken.
3446 ret = my_realpath(abspath, dir.c_str(), MYF(0));
4637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3446 times.
3446 ut_ad(ret == 0);
4638
4639 /* Concatenate the absolute path with the non-existing sub-path.
4640 NOTE: If this path existed, my_realpath() would put a separator
4641 at the end if it is a directory. But since the ghost portion
4642 does not yet exist, we don't know if it is a dir or a file, so
4643 we cannot attach a trailing separator for a directory. So we
4644 trim them off in Fil_path::is_same_as() and is_ancestor(). */
4645
1/2
✓ Branch 0 taken 3446 times.
✗ Branch 1 not taken.
3446 real_path.assign(abspath);
4646
1/2
✓ Branch 0 taken 3446 times.
✗ Branch 1 not taken.
3446 append_separator(real_path);
4647
1/2
✓ Branch 0 taken 3446 times.
✗ Branch 1 not taken.
3446 real_path.append(ghost);
4648 3446 }
4649 }
4650
4651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1059907 times.
1059907 if (lower_case_file_system) {
4652 Fil_path::to_lower(real_path);
4653 }
4654
4655 /* Try to consistently end a directory name with a separator.
4656 On Windows, my_realpath() usually puts a separator at the end
4657 of a directory path (it does not do that for the path ".").
4658 On non-Windows it never does.
4659 So if the separator is missing, decide whether to append it. */
4660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1059907 times.
1059907 ut_ad(!real_path.empty());
4661
2/2
✓ Branch 0 taken 1059901 times.
✓ Branch 1 taken 6 times.
1059907 if (!is_separator(real_path.back())) {
4662 1059901 bool add_sep = true;
4663
3/4
✓ Branch 0 taken 320197 times.
✓ Branch 1 taken 736260 times.
✓ Branch 2 taken 3444 times.
✗ Branch 3 not taken.
1059901 switch (path_type) {
4664 320197 case OS_FILE_TYPE_DIR:
4665 case OS_FILE_TYPE_BLOCK:
4666 320197 break;
4667 736260 case OS_FILE_TYPE_FILE:
4668 case OS_FILE_TYPE_LINK:
4669 736260 add_sep = false;
4670 736260 break;
4671 3444 case OS_FILE_TYPE_FAILED:
4672 case OS_FILE_TYPE_MISSING:
4673 case OS_FILE_TYPE_NAME_TOO_LONG:
4674 case OS_FILE_PERMISSION_ERROR:
4675 case OS_FILE_TYPE_UNKNOWN:
4676 /* This filepath is missing or cannot be identified for some other
4677 reason. If it ends in a three letter extension, assume it is a file
4678 name and do not add the trailing separator. Otherwise, assume it is
4679 intended to be a directory.*/
4680 3444 size_t s = real_path.size();
4681
5/8
✓ Branch 0 taken 3444 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2451 times.
✓ Branch 3 taken 993 times.
✓ Branch 4 taken 2451 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2451 times.
✗ Branch 7 not taken.
3444 if (s > 4 && real_path[s - 4] == '.' && real_path[s - 3] != '.' &&
4682
5/8
✓ Branch 0 taken 2451 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2343 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 2343 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2343 times.
✗ Branch 7 not taken.
2451 real_path[s - 2] != '.' && real_path[s - 1] != '.' &&
4683
5/8
✓ Branch 0 taken 3444 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2343 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2343 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2223 times.
✓ Branch 7 taken 1221 times.
9231 !is_separator(real_path[s - 3]) &&
4684
3/4
✓ Branch 0 taken 2343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2223 times.
✓ Branch 3 taken 120 times.
2343 !is_separator(real_path[s - 2])) {
4685 2223 add_sep = false;
4686 }
4687 }
4688
4689
2/2
✓ Branch 0 taken 321418 times.
✓ Branch 1 taken 738483 times.
1059901 if (add_sep) {
4690
1/2
✓ Branch 0 taken 321418 times.
✗ Branch 1 not taken.
321418 append_separator(real_path);
4691 }
4692 }
4693
4694 1059907 return real_path;
4695 1059908 }
4696
4697 2111740 std::string Fil_path::get_basename(const std::string &filepath) {
4698 2111740 auto sep = filepath.find_last_of(SEPARATOR);
4699
4700 return (sep == std::string::npos)
4701 ? filepath
4702
2/2
✓ Branch 0 taken 323544 times.
✓ Branch 1 taken 1788196 times.
2111740 : filepath.substr(sep + 1, filepath.length() - sep);
4703 }
4704
4705 /** Constructor
4706 @param[in] dir Directory that the files are under */
4707 12167 Tablespace_files::Tablespace_files(const std::string &dir)
4708
1/2
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
12167 : m_ibd_paths(), m_undo_paths(), m_dir(dir) {
4709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12167 times.
12167 ut_ad(Fil_path::is_separator(dir.back()));
4710 12167 }
4711
4712 /** Closes a single-table tablespace. The tablespace must be cached in the
4713 memory cache. Free all pages used by the tablespace.
4714 @param[in] space_id Tablespace ID
4715 @return DB_SUCCESS or error */
4716 396 dberr_t fil_close_tablespace(space_id_t space_id) {
4717
2/4
✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 396 times.
396 ut_ad(!fsp_is_undo_tablespace(space_id));
4718
2/4
✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 396 times.
396 ut_ad(!fsp_is_system_or_temp_tablespace(space_id));
4719
4720
1/2
✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
396 auto shard = fil_system->shard_by_id(space_id);
4721
4722 396 char *path{};
4723 396 fil_space_t *space{};
4724
4725
1/2
✓ Branch 0 taken 396 times.
✗ Branch 1 not taken.
396 auto err = shard->wait_for_pending_operations(space_id, space, &path);
4726
4727
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 217 times.
396 if (err != DB_SUCCESS) {
4728 179 return err;
4729 }
4730
4731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 217 times.
217 ut_a(path != nullptr);
4732
4733 #ifndef UNIV_HOTBACKUP
4734 217 shard->space_prepare_for_delete(space);
4735 #else
4736 rw_lock_x_lock(&space->latch, UT_LOCATION_HERE);
4737
4738 /* If the free is successful, the X lock will be released before
4739 the space memory data structure is freed. */
4740
4741 if (!fil_space_free(space_id, true)) {
4742 rw_lock_x_unlock(&space->latch);
4743 err = DB_TABLESPACE_NOT_FOUND;
4744 } else {
4745 err = DB_SUCCESS;
4746 }
4747 #endif /* !UNIV_HOTBACKUP */
4748
4749 /* Delete any generated files, otherwise if we drop the database the
4750 remove directory will fail. */
4751
4752
2/4
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 217 times.
✗ Branch 3 not taken.
217 auto cfg_name = Fil_path::make_cfg(path);
4753
4754
1/2
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
217 if (cfg_name != nullptr) {
4755
1/2
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
217 os_file_delete_if_exists(innodb_data_file_key, cfg_name, nullptr);
4756
4757 217 ut::free(cfg_name);
4758 }
4759
4760
2/4
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 217 times.
✗ Branch 3 not taken.
217 auto cfp_name = Fil_path::make_cfp(path);
4761
4762
1/2
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
217 if (cfp_name != nullptr) {
4763
1/2
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
217 os_file_delete_if_exists(innodb_data_file_key, cfp_name, nullptr);
4764
4765 217 ut::free(cfp_name);
4766 }
4767
4768 217 ut::free(path);
4769
4770 217 return err;
4771 }
4772
4773 #ifndef UNIV_HOTBACKUP
4774 /** Write a log record about an operation on a tablespace file.
4775 @param[in] type MLOG_FILE_OPEN or MLOG_FILE_DELETE
4776 or MLOG_FILE_CREATE or MLOG_FILE_RENAME
4777 @param[in] space_id Tablespace identifier
4778 @param[in] path File path
4779 @param[in] new_path If type is MLOG_FILE_RENAME, the new name
4780 @param[in] flags If type is MLOG_FILE_CREATE, the space flags
4781 @param[in,out] mtr Mini-transaction */
4782 496462 static void fil_op_write_log(mlog_id_t type, space_id_t space_id,
4783 const char *path, const char *new_path,
4784 uint32_t flags, mtr_t *mtr) {
4785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 496464 times.
496462 ut_ad(space_id != TRX_SYS_SPACE);
4786
4787 496464 byte *log_ptr = nullptr;
4788
4789
3/4
✓ Branch 0 taken 496463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 538 times.
✓ Branch 3 taken 495925 times.
496464 if (!mlog_open(mtr, 11 + 4 + 2 + 1, log_ptr)) {
4790 /* Logging in mtr is switched off during crash recovery:
4791 in that case mlog_open returns nullptr */
4792 538 return;
4793 }
4794
4795
1/2
✓ Branch 0 taken 495925 times.
✗ Branch 1 not taken.
495925 log_ptr = mlog_write_initial_log_record_low(type, space_id, 0, log_ptr, mtr);
4796
4797
2/2
✓ Branch 0 taken 195540 times.
✓ Branch 1 taken 300385 times.
495925 if (type == MLOG_FILE_CREATE) {
4798
1/2
✓ Branch 0 taken 195541 times.
✗ Branch 1 not taken.
195540 mach_write_to_4(log_ptr, flags);
4799 195541 log_ptr += 4;
4800 }
4801
4802 /* Let us store the strings as null-terminated for easier readability
4803 and handling */
4804
4805 495926 ulint len = strlen(path) + 1;
4806
4807
1/2
✓ Branch 0 taken 495926 times.
✗ Branch 1 not taken.
495926 mach_write_to_2(log_ptr, len);
4808 495926 log_ptr += 2;
4809
4810
1/2
✓ Branch 0 taken 495926 times.
✗ Branch 1 not taken.
495926 mlog_close(mtr, log_ptr);
4811
4812
1/2
✓ Branch 0 taken 495924 times.
✗ Branch 1 not taken.
495926 mlog_catenate_string(mtr, reinterpret_cast<const byte *>(path), len);
4813
4814
2/3
✓ Branch 0 taken 103237 times.
✓ Branch 1 taken 392687 times.
✗ Branch 2 not taken.
495924 switch (type) {
4815 103237 case MLOG_FILE_RENAME:
4816
4817
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103237 times.
103237 ut_ad(strchr(new_path, Fil_path::OS_SEPARATOR) != nullptr);
4818
4819 103237 len = strlen(new_path) + 1;
4820
4821
2/4
✓ Branch 0 taken 103237 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103237 times.
103237 ut_a(mlog_open(mtr, 2 + len, log_ptr));
4822
4823
1/2
✓ Branch 0 taken 103237 times.
✗ Branch 1 not taken.
103237 mach_write_to_2(log_ptr, len);
4824
4825 103237 log_ptr += 2;
4826
4827
1/2
✓ Branch 0 taken 103237 times.
✗ Branch 1 not taken.
103237 mlog_close(mtr, log_ptr);
4828
4829
1/2
✓ Branch 0 taken 103237 times.
✗ Branch 1 not taken.
103237 mlog_catenate_string(mtr, reinterpret_cast<const byte *>(new_path), len);
4830 103237 break;
4831 392687 case MLOG_FILE_DELETE:
4832 case MLOG_FILE_CREATE:
4833 392687 break;
4834 default:
4835 ut_d(ut_error);
4836 }
4837 }
4838
4839 5 bool fil_system_get_file_by_space_id(space_id_t space_id, std::string &name) {
4840
3/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 ut_a(dict_sys_t::is_reserved(space_id) || srv_is_upgrade_mode);
4841
4842 5 return fil_system->get_file_by_space_id(space_id, name);
4843 }
4844
4845 1477403 bool fil_system_get_file_by_space_num(space_id_t space_num,
4846 space_id_t &space_id, std::string &name) {
4847 1477403 return fil_system->get_file_by_space_num(space_num, space_id, name);
4848 }
4849
4850 #endif /* !UNIV_HOTBACKUP */
4851
4852 197365 dberr_t Fil_shard::space_delete(space_id_t space_id, buf_remove_t buf_remove) {
4853 197365 char *path = nullptr;
4854 197365 fil_space_t *space = nullptr;
4855
4856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197365 times.
197365 ut_ad(!fsp_is_system_tablespace(space_id));
4857
2/4
✓ Branch 0 taken 197365 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197365 times.
197365 ut_ad(!fsp_is_global_temporary(space_id));
4858
4859
1/2
✓ Branch 0 taken 197365 times.
✗ Branch 1 not taken.
197365 dberr_t err = wait_for_pending_operations(space_id, space, &path);
4860
4861
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 197330 times.
197365 if (err != DB_SUCCESS) {
4862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 ut_a(err == DB_TABLESPACE_NOT_FOUND);
4863 35 return err;
4864 }
4865
4866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197330 times.
197330 ut_a(path != nullptr);
4867
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197330 times.
197330 ut_a(space != nullptr);
4868
4869 #ifndef UNIV_HOTBACKUP
4870 /* IMPORTANT: Because we have set space::stop_new_ops there
4871 can't be any new ibuf merges, reads or flushes. We are here
4872 because file::n_pending was zero above. However, it is still
4873 possible to have pending read and write requests:
4874
4875 A read request can happen because the reader thread has
4876 gone through the ::stop_new_ops check in buf_page_init_for_read()
4877 before the flag was set and has not yet incremented ::n_pending
4878 when we checked it above.
4879
4880 A write request can be issued any time because we don't check
4881 the ::stop_new_ops flag when queueing a block for write.
4882
4883 We deal with pending write requests in the following function
4884 where we'd minimally evict all dirty pages belonging to this
4885 space from the flush_list. Note that if a block is IO-fixed
4886 we'll wait for IO to complete.
4887
4888 For buf_remove == BUF_REMOVE_NONE we mark the fil_space_t instance
4889 as deleted by bumping up the file_space_t::m_version. All pages
4890 that are less than this version number will be discarded. We wait
4891 for any pending IO to complete after that.
4892
4893 To deal with potential read requests, we will check the
4894 ::stop_new_ops flag in fil_io(). */
4895
4896
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 197325 times.
197330 if (buf_remove != BUF_REMOVE_NONE) {
4897
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 buf_LRU_flush_or_remove_pages(space_id, buf_remove, nullptr);
4898 }
4899
4900 /* Ensure that we write redo log for the operation also within the Clone
4901 notifier block. This is needed because we don't have any mechanism today
4902 to avoid checkpoint crossing the redo log before the actual operation
4903 is complete. Make sure we are not holding shard mutex. */
4904
2/4
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197330 times.
197330 ut_ad(!mutex_owned());
4905
1/2
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
197330 Clone_notify notifier(Clone_notify::Type::SPACE_DROP, space_id, false);
4906
4907
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197330 times.
197330 if (notifier.failed()) {
4908 /* Currently post DDL operations are never rolled back. */
4909 /* purecov: begin deadcode */
4910 ut::free(path);
4911 ut_d(ut_error);
4912 ut_o(return DB_ERROR);
4913 /* purecov: end */
4914 }
4915 #endif /* !UNIV_HOTBACKUP */
4916
4917 /* If it is a delete then also delete any generated files, otherwise
4918 when we drop the database the remove directory will fail. */
4919
1/2
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
197330 if (space->purpose != FIL_TYPE_TEMPORARY) {
4920 #ifdef UNIV_HOTBACKUP
4921 /* When replaying the operation in MySQL Enterprise
4922 Backup, we do not try to write any log record. */
4923 #else /* UNIV_HOTBACKUP */
4924 /* Before deleting the file, write a log record about it, so that
4925 InnoDB crash recovery will expect the file to be gone. */
4926
1/2
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
197330 mtr_t mtr;
4927
4928
1/2
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
197330 mtr.start();
4929
4930
1/2
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
197330 fil_op_write_log(MLOG_FILE_DELETE, space_id, path, nullptr, 0, &mtr);
4931
4932
1/2
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
197330 mtr.commit();
4933
4934
5/8
✓ Branch 0 taken 197330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 197329 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
197330 DBUG_EXECUTE_IF("delete_crash", log_buffer_flush_to_disk();
4935 DBUG_SUICIDE(););
4936
4937 /* Even if we got killed shortly after deleting the
4938 tablespace file, the record must have already been
4939 written to the redo log. */
4940
2/4
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197329 times.
✗ Branch 3 not taken.
197329 log_write_up_to(*log_sys, mtr.commit_lsn(), true);
4941 #endif /* UNIV_HOTBACKUP */
4942
4943
2/4
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197329 times.
✗ Branch 3 not taken.
197329 char *cfg_name = Fil_path::make_cfg(path);
4944
4945
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 if (cfg_name != nullptr) {
4946
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 os_file_delete_if_exists(innodb_data_file_key, cfg_name, nullptr);
4947
4948 197329 ut::free(cfg_name);
4949 }
4950
4951
2/4
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197329 times.
✗ Branch 3 not taken.
197329 char *cfp_name = Fil_path::make_cfp(path);
4952
4953
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 if (cfp_name != nullptr) {
4954
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 os_file_delete_if_exists(innodb_data_file_key, cfp_name, nullptr);
4955
4956 197329 ut::free(cfp_name);
4957 }
4958 197329 }
4959
4960
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 mutex_acquire();
4961
4962 /* Double check the sanity of pending ops after reacquiring
4963 the fil_system::mutex. */
4964
2/4
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 197329 times.
✗ Branch 3 not taken.
197329 if (const fil_space_t *s = get_space_by_id(space_id)) {
4965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197329 times.
197329 ut_a(s == space);
4966
4967
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 space->set_deleted();
4968
4969 #ifndef UNIV_HOTBACKUP
4970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197329 times.
197329 ut_a(space->files.size() == 1);
4971 197329 auto &file = space->files.front();
4972
4973 /* Wait for any pending writes. */
4974
3/4
✓ Branch 0 taken 8984 times.
✓ Branch 1 taken 197329 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 197329 times.
206313 while (file.n_pending_ios > 0 || file.n_pending_flushes > 0 ||
4975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197329 times.
197329 file.is_being_extended) {
4976 /* Release and reacquire the mutex because we want the IO to complete. */
4977
1/2
✓ Branch 0 taken 8984 times.
✗ Branch 1 not taken.
8984 mutex_release();
4978
4979 8984 std::this_thread::yield();
4980
4981
1/2
✓ Branch 0 taken 8984 times.
✗ Branch 1 not taken.
8984 mutex_acquire();
4982 }
4983
4984
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 m_deleted_spaces.push_back({space->id, space});
4985 #endif /* !UNIV_HOTBACKUP */
4986
4987
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 space_detach(space);
4988
4989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197329 times.
197329 ut_a(space->files.size() == 1);
4990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197329 times.
197329 ut_a(space->files.front().n_pending_ios == 0);
4991
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 space_remove_from_lookup_maps(space_id);
4992
4993
1/2
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
197329 mutex_release();
4994
4995 #ifdef UNIV_HOTBACKUP
4996 /* For usage inside MEB we don't support lazy stale page eviction, we just
4997 do what fil_shard::purge() does directly here. */
4998 space_free_low(space);
4999 #endif /* UNIV_HOTBACKUP */
5000
5001
3/6
✓ Branch 0 taken 197329 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197329 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 197329 times.
197329 if (!os_file_delete(innodb_data_file_key, path) &&
5002 !os_file_delete_if_exists(innodb_data_file_key, path, nullptr)) {
5003 /* Note: This is because we have removed the
5004 tablespace instance from the cache. */
5005
5006 err = DB_IO_ERROR;
5007 }
5008 } else {
5009 mutex_release();
5010
5011 err = DB_TABLESPACE_NOT_FOUND;
5012 }
5013
5014 197329 ut::free(path);
5015 197329 return err;
5016 197329 }
5017
5018 197365 dberr_t fil_delete_tablespace(space_id_t space_id, buf_remove_t buf_remove) {
5019 197365 auto shard = fil_system->shard_by_id(space_id);
5020
5021 197365 return shard->space_delete(space_id, buf_remove);
5022 }
5023
5024 88041 dberr_t Fil_shard::space_prepare_for_truncate(space_id_t space_id,
5025 fil_space_t *&space) {
5026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88041 times.
88041 ut_ad(space_id != TRX_SYS_SPACE);
5027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88041 times.
88041 ut_ad(!fsp_is_system_tablespace(space_id));
5028
2/4
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88041 times.
88041 ut_ad(!fsp_is_global_temporary(space_id));
5029
5030 88041 char *path{};
5031
1/2
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
88041 auto err = wait_for_pending_operations(space_id, space, &path);
5032
5033 88041 ut::free(path);
5034
5035 88041 return err;
5036 }
5037
5038 88041 bool Fil_shard::space_truncate(space_id_t space_id, page_no_t size_in_pages) {
5039 #ifndef UNIV_HOTBACKUP
5040 88041 fil_space_t *space{};
5041
5042 /* Step-1: Prepare tablespace for truncate. This involves
5043 stopping all the new operations + IO on that tablespace. Any future attempts
5044 to flush will be ignored and pages discarded. */
5045
2/4
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88041 times.
88041 if (space_prepare_for_truncate(space_id, space) != DB_SUCCESS) {
5046 return false;
5047 }
5048
5049
1/2
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
88041 mutex_acquire();
5050
5051 /* Step-2: Mark the tablespace pages in the buffer pool as stale by bumping
5052 the version number of the space. Those stale pages will be ignored and freed
5053 lazily later. This includes AHI, for which entries will be removed on
5054 buf_page_free_stale*() -> buf_LRU_free_page ->
5055 btr_search_drop_page_hash_index() */
5056
1/2
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
88041 space->bump_version();
5057
5058 /* Step-3: Truncate the tablespace and accordingly update
5059 the fil_space_t handler that is used to access this tablespace. */
5060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88041 times.
88041 ut_a(space->files.size() == 1);
5061
5062 88041 auto &file = space->files.front();
5063
5064
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 87968 times.
88041 if (!file.is_open) {
5065
2/4
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
73 if (!open_file(&file)) {
5066 mutex_release();
5067 return false;
5068 }
5069 }
5070
5071 88041 space->size = file.size = size_in_pages;
5072
5073
1/2
✓ Branch 0 taken 88039 times.
✗ Branch 1 not taken.
88041 bool success = os_file_truncate(file.name, file.handle, 0);
5074
5075
1/2
✓ Branch 0 taken 88039 times.
✗ Branch 1 not taken.
88039 if (success) {
5076 88039 os_offset_t size = size_in_pages * UNIV_PAGE_SIZE;
5077
5078
1/2
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
88039 success = os_file_set_size(file.name, file.handle, 0, size, true);
5079
5080
1/2
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
88041 if (success) {
5081 88041 space->stop_new_ops = false;
5082 }
5083 }
5084
5085
1/2
✓ Branch 0 taken 88041 times.
✗ Branch 1 not taken.
88041 mutex_release();
5086
5087 88041 return success;
5088 #else
5089 /* Truncating a tablespace is not supported for MEB. */
5090 ut_error;
5091 #endif
5092 }
5093
5094 /** Truncate the tablespace to needed size.
5095 @param[in] space_id Tablespace ID to truncate
5096 @param[in] size_in_pages Truncate size.
5097 @return true if truncate was successful. */
5098 88041 bool fil_truncate_tablespace(space_id_t space_id, page_no_t size_in_pages) {
5099 88041 auto shard = fil_system->shard_by_id(space_id);
5100
5101 88041 return shard->space_truncate(space_id, size_in_pages);
5102 }
5103
5104 #ifdef UNIV_DEBUG
5105 /** Increase redo skipped count for a tablespace.
5106 @param[in] space_id Tablespace ID */
5107 45146 void fil_space_inc_redo_skipped_count(space_id_t space_id) {
5108 45146 auto shard = fil_system->shard_by_id(space_id);
5109
5110 45145 shard->mutex_acquire();
5111
5112 45146 fil_space_t *space = shard->get_space_by_id(space_id);
5113
5114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45146 times.
45146 ut_a(space != nullptr);
5115
5116 45146 ++space->redo_skipped_count;
5117
5118 45146 shard->mutex_release();
5119 45146 }
5120
5121 /** Decrease redo skipped count for a tablespace.
5122 @param[in] space_id Tablespace ID */
5123 45146 void fil_space_dec_redo_skipped_count(space_id_t space_id) {
5124 45146 auto shard = fil_system->shard_by_id(space_id);
5125
5126 45146 shard->mutex_acquire();
5127
5128 45146 fil_space_t *space = shard->get_space_by_id(space_id);
5129
5130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45146 times.
45146 ut_a(space != nullptr);
5131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45146 times.
45146 ut_a(space->redo_skipped_count > 0);
5132
5133 45146 --space->redo_skipped_count;
5134
5135 45146 shard->mutex_release();
5136 45146 }
5137
5138 /** Check whether a single-table tablespace is redo skipped.
5139 @param[in] space_id Tablespace ID
5140 @return true if redo skipped */
5141 177978 bool fil_space_is_redo_skipped(space_id_t space_id) {
5142 177978 auto shard = fil_system->shard_by_id(space_id);
5143
5144 177978 shard->mutex_acquire();
5145
5146 177978 fil_space_t *space = shard->get_space_by_id(space_id);
5147
5148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177978 times.
177978 ut_a(space != nullptr);
5149
5150 177978 bool is_redo_skipped = space->redo_skipped_count > 0;
5151
5152 177978 shard->mutex_release();
5153
5154 177978 return is_redo_skipped;
5155 }
5156 #endif /* UNIV_DEBUG */
5157
5158 #ifndef UNIV_HOTBACKUP
5159
5160 /** Discards a single-table tablespace. The tablespace must be cached in the
5161 memory cache. Discarding is like deleting a tablespace, but
5162
5163 1. We do not drop the table from the data dictionary;
5164
5165 2. We remove all insert buffer entries for the tablespace immediately;
5166 in DROP TABLE they are only removed gradually in the background;
5167
5168 3. When the user does IMPORT TABLESPACE, the tablespace will have the
5169 same id as it originally had.
5170
5171 4. Free all the pages in use by the tablespace if rename=true.
5172 @param[in] space_id Tablespace ID
5173 @return DB_SUCCESS or error */
5174 890 dberr_t fil_discard_tablespace(space_id_t space_id) {
5175 dberr_t err;
5176
5177 890 err = fil_delete_tablespace(space_id, BUF_REMOVE_NONE);
5178
5179
2/4
✓ Branch 0 taken 875 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
890 switch (err) {
5180 875 case DB_SUCCESS:
5181 875 break;
5182
5183 case DB_IO_ERROR:
5184
5185 ib::warn(ER_IB_MSG_291, ulong{space_id}, ut_strerr(err));
5186 break;
5187
5188 15 case DB_TABLESPACE_NOT_FOUND:
5189
5190
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 ib::warn(ER_IB_MSG_292, ulong{space_id}, ut_strerr(err));
5191 15 break;
5192
5193 default:
5194 ut_error;
5195 }
5196
5197 890 return err;
5198 }
5199
5200 /** Write redo log for renaming a file.
5201 @param[in] space_id Tablespace id
5202 @param[in] old_name Tablespace file name
5203 @param[in] new_name Tablespace file name after renaming
5204 @param[in,out] mtr Mini-transaction */
5205 103416 static void fil_name_write_rename(space_id_t space_id, const char *old_name,
5206 const char *new_name, mtr_t *mtr) {
5207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103416 times.
103416 ut_ad(!fsp_is_system_or_temp_tablespace(space_id));
5208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103416 times.
103416 ut_ad(!fsp_is_undo_tablespace(space_id));
5209
5210 /* Note: A checkpoint can take place here. */
5211
5212
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 103415 times.
103416 DBUG_EXECUTE_IF("ib_crash_rename_log_1", DBUG_SUICIDE(););
5213
5214 static const auto type = MLOG_FILE_RENAME;
5215
5216 103415 fil_op_write_log(type, space_id, old_name, new_name, 0, mtr);
5217
5218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103415 times.
103415 DBUG_EXECUTE_IF("ib_crash_rename_log_2", DBUG_SUICIDE(););
5219
5220 /* Note: A checkpoint can take place here too before we
5221 have physically renamed the file. */
5222 103415 }
5223
5224 #ifdef UNIV_LINUX
5225 /* Write a redo log record for adding pages to a tablespace
5226 @param[in] space_id Space ID
5227 @param[in] offset Offset from where the file
5228 is extended
5229 @param[in] size Number of bytes by which the file
5230 is extended starting from the offset
5231 @param[in,out] mtr Mini-transaction */
5232 199762 static void fil_op_write_space_extend(space_id_t space_id, os_offset_t offset,
5233 os_offset_t size, mtr_t *mtr) {
5234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199762 times.
199762 ut_ad(space_id != TRX_SYS_SPACE);
5235
5236 byte *log_ptr;
5237
5238
3/4
✓ Branch 0 taken 199762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 368 times.
✓ Branch 3 taken 199394 times.
199762 if (!mlog_open(mtr, 7 + 8 + 8, log_ptr)) {
5239 /* Logging in mtr is switched off during crash recovery:
5240 in that case mlog_open returns nullptr */
5241 368 return;
5242 }
5243
5244 #ifdef UNIV_DEBUG
5245 199394 byte *start_log = log_ptr;
5246 #endif /* UNIV_DEBUG */
5247
5248
1/2
✓ Branch 0 taken 199394 times.
✗ Branch 1 not taken.
199394 log_ptr = mlog_write_initial_log_record_low(MLOG_FILE_EXTEND, space_id, 0,
5249 log_ptr, mtr);
5250
5251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199394 times.
199394 ut_ad(size > 0);
5252
5253 /* Write the starting offset in the file */
5254
1/2
✓ Branch 0 taken 199394 times.
✗ Branch 1 not taken.
199394 mach_write_to_8(log_ptr, offset);
5255 199394 log_ptr += 8;
5256
5257 /* Write the size by which file needs to be extended from
5258 the given offset */
5259
1/2
✓ Branch 0 taken 199394 times.
✗ Branch 1 not taken.
199394 mach_write_to_8(log_ptr, size);
5260 199394 log_ptr += 8;
5261
5262 #ifdef UNIV_DEBUG
5263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199394 times.
199394 ut_ad(log_ptr <= start_log + 23);
5264 #endif /* UNIV_DEBUG */
5265
5266
1/2
✓ Branch 0 taken 199394 times.
✗ Branch 1 not taken.
199394 mlog_close(mtr, log_ptr);
5267 }
5268 #endif
5269 #endif /* !UNIV_HOTBACKUP */
5270
5271 /** Allocate and build a file name from a path, a table or tablespace name
5272 and a suffix.
5273 @param[in] path_in nullptr or the direcory path or the full path
5274 and filename
5275 @param[in] name_in nullptr if path is full, or Table/Tablespace
5276 name
5277 @param[in] ext the file extension to use
5278 @param[in] trim whether last name on the path should be trimmed
5279 @return own: file name; must be freed by ut::free() */
5280 1170601 char *Fil_path::make(const std::string &path_in, const std::string &name_in,
5281 ib_file_suffix ext, bool trim) {
5282 /* The path should be a directory and should not contain the
5283 basename of the file. If the path is empty, we will use the
5284 default path, */
5285
5286
4/6
✓ Branch 0 taken 730498 times.
✓ Branch 1 taken 440105 times.
✓ Branch 2 taken 730499 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1170604 times.
1170601 ut_ad(!path_in.empty() || !name_in.empty());
5287
5288 1170604 std::string path;
5289
5290
2/2
✓ Branch 0 taken 730499 times.
✓ Branch 1 taken 440104 times.
1170603 if (path_in.empty()) {
5291
2/4
✓ Branch 0 taken 730499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 730499 times.
730499 if (is_absolute_path(name_in)) {
5292 path = "";
5293 } else {
5294
1/2
✓ Branch 0 taken 730499 times.
✗ Branch 1 not taken.
730499 path.assign(MySQL_datadir_path);
5295 }
5296 } else {
5297
1/2
✓ Branch 0 taken 440104 times.
✗ Branch 1 not taken.
440104 path.assign(path_in);
5298 }
5299
5300 1170603 std::string name;
5301
5302
2/2
✓ Branch 0 taken 774851 times.
✓ Branch 1 taken 395754 times.
1170603 if (!name_in.empty()) {
5303
1/2
✓ Branch 0 taken 774849 times.
✗ Branch 1 not taken.
774851 name.assign(name_in);
5304 }
5305
5306 /* Do not prepend the datadir path (which must be DOT_SLASH)
5307 if the name is an absolute path or a relative path like
5308 DOT_SLASH or DOT_DOT_SLASH. */
5309
11/18
✓ Branch 0 taken 1170605 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1170602 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1170602 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1170602 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1170592 times.
✓ Branch 9 taken 10 times.
✓ Branch 10 taken 1170601 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 16 times.
✓ Branch 13 taken 1170586 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
3511799 if (is_absolute_path(name) || has_prefix(name, DOT_SLASH) ||
5310
10/16
✓ Branch 0 taken 1170592 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1170592 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1170589 times.
✓ Branch 6 taken 1170592 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 1170592 times.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 1170601 times.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
2341197 has_prefix(name, DOT_DOT_SLASH)) {
5311 16 path.clear();
5312 }
5313
5314 1170602 std::string filepath;
5315
5316
2/2
✓ Branch 0 taken 1170587 times.
✓ Branch 1 taken 12 times.
1170598 if (!path.empty()) {
5317
1/2
✓ Branch 0 taken 1170587 times.
✗ Branch 1 not taken.
1170587 filepath.assign(path);
5318 }
5319
5320
2/2
✓ Branch 0 taken 4918 times.
✓ Branch 1 taken 1165681 times.
1170599 if (trim) {
5321 /* Find the offset of the last DIR separator and set it to
5322 null in order to strip off the old basename from this path. */
5323 4918 auto pos = filepath.find_last_of(SEPARATOR);
5324
5325
1/2
✓ Branch 0 taken 4918 times.
✗ Branch 1 not taken.
4918 if (pos != std::string::npos) {
5326
1/2
✓ Branch 0 taken 4918 times.
✗ Branch 1 not taken.
4918 filepath.resize(pos);
5327 }
5328 }
5329
5330
2/2
✓ Branch 0 taken 774850 times.
✓ Branch 1 taken 395754 times.
1170599 if (!name.empty()) {
5331
1/2
✓ Branch 0 taken 774851 times.
✗ Branch 1 not taken.
774850 append_separator(filepath);
5332
5333
1/2
✓ Branch 0 taken 774846 times.
✗ Branch 1 not taken.
774851 filepath.append(name);
5334 }
5335
5336 /* Make sure that the specified suffix is at the end. */
5337
2/2
✓ Branch 0 taken 1128356 times.
✓ Branch 1 taken 42244 times.
1170600 if (ext != NO_EXT) {
5338 1128356 const auto suffix = dot_ext[ext];
5339 1128356 size_t len = strlen(suffix);
5340
5341 /* This assumes that the suffix starts with '.'. If the
5342 first char of the suffix is found in the filepath at the
5343 same length as the suffix from the end, then we will assume
5344 that there is a previous suffix that needs to be replaced. */
5345
5346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1128356 times.
1128356 ut_ad(*suffix == '.');
5347
5348
5/6
✓ Branch 0 taken 1128356 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 396508 times.
✓ Branch 3 taken 731848 times.
✓ Branch 4 taken 396508 times.
✓ Branch 5 taken 731848 times.
1128356 if (filepath.length() > len && *(filepath.end() - len) == *suffix) {
5349
1/2
✓ Branch 0 taken 396508 times.
✗ Branch 1 not taken.
396508 filepath.replace(filepath.end() - len, filepath.end(), suffix);
5350 } else {
5351
1/2
✓ Branch 0 taken 731848 times.
✗ Branch 1 not taken.
731848 filepath.append(suffix);
5352 }
5353 }
5354
5355 1170600 normalize(filepath);
5356
5357
1/2
✓ Branch 0 taken 1170605 times.
✗ Branch 1 not taken.
2341210 return mem_strdup(filepath.c_str());
5358 1170605 }
5359
5360 285791 bool Fil_path::parse_file_path(const std::string &file_path,
5361 ib_file_suffix extn, std::string &dict_name) {
5362
1/2
✓ Branch 0 taken 285791 times.
✗ Branch 1 not taken.
285791 dict_name.assign(file_path);
5363
3/4
✓ Branch 0 taken 285791 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 506 times.
✓ Branch 3 taken 285285 times.
285791 if (!Fil_path::truncate_suffix(extn, dict_name)) {
5364 506 dict_name.clear();
5365 506 return false;
5366 }
5367
5368 /* Extract table name */
5369 285285 auto table_pos = dict_name.find_last_of(SEPARATOR);
5370
2/2
✓ Branch 0 taken 847 times.
✓ Branch 1 taken 284438 times.
285285 if (table_pos == std::string::npos) {
5371 847 dict_name.clear();
5372 847 return false;
5373 }
5374
1/2
✓ Branch 0 taken 284438 times.
✗ Branch 1 not taken.
284438 std::string table_name = dict_name.substr(table_pos + 1);
5375
1/2
✓ Branch 0 taken 284438 times.
✗ Branch 1 not taken.
284438 dict_name.resize(table_pos);
5376
5377 /* Extract schema name */
5378 284438 auto schema_pos = dict_name.find_last_of(SEPARATOR);
5379
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 284406 times.
284438 if (schema_pos == std::string::npos) {
5380 32 dict_name.clear();
5381 32 return false;
5382 }
5383
1/2
✓ Branch 0 taken 284406 times.
✗ Branch 1 not taken.
284406 std::string schema_name = dict_name.substr(schema_pos + 1);
5384
5385 /* Build dictionary table name schema/table form. */
5386
1/2
✓ Branch 0 taken 284406 times.
✗ Branch 1 not taken.
284406 dict_name.assign(schema_name);
5387
1/2
✓ Branch 0 taken 284406 times.
✗ Branch 1 not taken.
284406 dict_name.push_back(DB_SEPARATOR);
5388
1/2
✓ Branch 0 taken 284406 times.
✗ Branch 1 not taken.
284406 dict_name.append(table_name);
5389 284406 return true;
5390 284438 }
5391
5392 49343 std::string Fil_path::make_new_path(const std::string &path_in,
5393 const std::string &name_in,
5394 ib_file_suffix extn) {
5395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49343 times.
49343 ut_a(Fil_path::has_suffix(extn, path_in));
5396
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49343 times.
49343 ut_a(!Fil_path::has_suffix(extn, name_in));
5397
5398 49343 std::string path(path_in);
5399
5400 49343 auto pos = path.find_last_of(SEPARATOR);
5401
5402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49343 times.
49343 ut_a(pos != std::string::npos);
5403
5404
1/2
✓ Branch 0 taken 49343 times.
✗ Branch 1 not taken.
49343 path.resize(pos);
5405
5406 49343 pos = path.find_last_of(SEPARATOR);
5407
5408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49343 times.
49343 ut_a(pos != std::string::npos);
5409
5410
1/2
✓ Branch 0 taken 49343 times.
✗ Branch 1 not taken.
49343 path.resize(pos + 1);
5411
5412
2/4
✓ Branch 0 taken 49343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49343 times.
✗ Branch 3 not taken.
49343 path.append(name_in + dot_ext[extn]);
5413
5414 49343 normalize(path);
5415
5416 49343 return path;
5417 }
5418
5419 /** This function reduces a null-terminated full remote path name
5420 into the path that is sent by MySQL for DATA DIRECTORY clause.
5421 It replaces the 'databasename/tablename.ibd' found at the end of the
5422 path with just 'tablename'.
5423
5424 Since the result is always smaller than the path sent in, no new
5425 memory is allocated. The caller should allocate memory for the path
5426 sent in. This function manipulates that path in place. If the path
5427 format is not as expected, set data_dir_path to "" and return.
5428
5429 The result is used to inform a SHOW CREATE TABLE command.
5430 @param[in,out] data_dir_path Full path/data_dir_path */
5431 184 void Fil_path::make_data_dir_path(char *data_dir_path) {
5432 /* Replace the period before the extension with a null byte. */
5433
3/6
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 184 times.
184 ut_ad(has_suffix(IBD, data_dir_path));
5434 184 char *dot = strrchr((char *)data_dir_path, '.');
5435 184 *dot = '\0';
5436
5437 /* The tablename starts after the last slash. */
5438 184 char *base_slash = strrchr((char *)data_dir_path, OS_PATH_SEPARATOR);
5439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
184 ut_ad(base_slash != nullptr);
5440
5441 184 *base_slash = '\0';
5442
5443
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 std::string base_name{base_slash + 1};
5444
5445 /* The database name starts after the next to last slash. */
5446 184 char *db_slash = strrchr((char *)data_dir_path, OS_SEPARATOR);
5447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
184 ut_ad(db_slash != nullptr);
5448 184 char *db_name = db_slash + 1;
5449
5450 /* Overwrite the db_name with the base_name. */
5451 184 memmove(db_name, base_name.c_str(), base_name.length());
5452 184 db_name[base_name.length()] = '\0';
5453 184 }
5454
5455 /** Test if a tablespace file can be renamed to a new filepath by checking
5456 if that the old filepath exists and the new filepath does not exist.
5457 @param[in] space_id Tablespace ID
5458 @param[in] old_path Old filepath
5459 @param[in] new_path New filepath
5460 @param[in] is_discarded Whether the tablespace is discarded
5461 @return innodb error code */
5462 122601 dberr_t fil_rename_tablespace_check(space_id_t space_id, const char *old_path,
5463 const char *new_path, bool is_discarded) {
5464 bool exists;
5465 os_file_type_t ftype;
5466
5467
6/10
✓ Branch 0 taken 122597 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 122597 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 122597 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 122597 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 122601 times.
122601 if (!is_discarded && os_file_status(old_path, &exists, &ftype) && !exists) {
5468 ib::error(ER_IB_MSG_293, old_path, new_path, ulong{space_id});
5469 return DB_TABLESPACE_NOT_FOUND;
5470 }
5471
5472
6/8
✓ Branch 0 taken 122601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122601 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 122590 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 122590 times.
122601 if (!os_file_status(new_path, &exists, &ftype) || exists) {
5473
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 ib::error(ER_IB_MSG_294, old_path, new_path, ulong{space_id});
5474 11 return DB_TABLESPACE_EXISTS;
5475 }
5476
5477 122590 return DB_SUCCESS;
5478 }
5479
5480 /** Rename a single-table tablespace.
5481 The tablespace must exist in the memory cache.
5482 @param[in] space_id Tablespace ID
5483 @param[in] old_path Old file name
5484 @param[in] new_name New tablespace name in the schema/space
5485 @param[in] new_path_in New file name, or nullptr if it is located
5486 in the normal data directory
5487 @return InnoDB error code */
5488 103578 dberr_t Fil_shard::space_rename(space_id_t space_id, const char *old_path,
5489 const char *new_name, const char *new_path_in) {
5490 fil_space_t *space;
5491 103578 ulint count = 0;
5492 103578 fil_node_t *file = nullptr;
5493 103578 bool write_ddl_log = true;
5494 103578 auto start_time = std::chrono::steady_clock::now();
5495
5496 #ifdef UNIV_DEBUG
5497 static uint32_t crash_injection_rename_tablespace_counter = 1;
5498 #endif /* UNIV_DEBUG */
5499
5500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103578 times.
103578 ut_a(space_id != TRX_SYS_SPACE);
5501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103578 times.
103578 ut_ad(strchr(new_name, '/') != nullptr);
5502
5503 for (;;) {
5504 207327 bool retry = false;
5505 207327 bool flush = false;
5506
5507 207327 ++count;
5508
5509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207327 times.
207327 if (!(count % 1000)) {
5510 ib::warn(ER_IB_MSG_295, old_path, ulong{space_id}, ulonglong{count});
5511 }
5512
5513 /* The name map and space ID map are in the same shard. */
5514
1/2
✓ Branch 0 taken 207327 times.
✗ Branch 1 not taken.
207327 mutex_acquire();
5515
5516
1/2
✓ Branch 0 taken 207327 times.
✗ Branch 1 not taken.
207327 space = get_space_by_id(space_id);
5517
5518
3/4
✓ Branch 0 taken 207327 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 207326 times.
207327 DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = nullptr;);
5519
5520
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 207326 times.
207327 if (space == nullptr) {
5521
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ib::error(ER_IB_MSG_296, ulong{space_id}, old_path);
5522
5523
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mutex_release();
5524
5525 1 return DB_ERROR;
5526
5527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207326 times.
207326 } else if (space->prevent_file_open) {
5528 /* Some other thread has stopped the IO. We need to
5529 wait for the other thread to complete its operation. */
5530 mutex_release();
5531
5532 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
5533 ib::warn(ER_IB_MSG_297);
5534
5535 start_time = std::chrono::steady_clock::now();
5536 }
5537
5538 std::this_thread::sleep_for(std::chrono::seconds(1));
5539
5540 continue;
5541
5542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207326 times.
207326 } else if (count > 25000) {
5543 mutex_release();
5544
5545 return DB_ERROR;
5546
5547
2/4
✓ Branch 0 taken 207326 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 207326 times.
207326 } else if (space != get_space_by_name(space->name)) {
5548 ib::error(ER_IB_MSG_298, space->name);
5549
5550 mutex_release();
5551
5552 return DB_ERROR;
5553
5554 } else {
5555
1/2
✓ Branch 0 taken 207326 times.
✗ Branch 1 not taken.
207326 auto new_space = get_space_by_name(new_name);
5556
5557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207326 times.
207326 if (new_space != nullptr) {
5558 if (new_space == space) {
5559 mutex_release();
5560
5561 return DB_SUCCESS;
5562 }
5563
5564 ut_a(new_space->id == space->id);
5565 }
5566 }
5567
5568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207326 times.
207326 ut_a(space->files.size() == 1);
5569
5570 #ifndef UNIV_HOTBACKUP
5571 /* Don't write DDL log during recovery when log_ddl is
5572 not initialized. */
5573
5574
3/4
✓ Branch 0 taken 103577 times.
✓ Branch 1 taken 103749 times.
✓ Branch 2 taken 103577 times.
✗ Branch 3 not taken.
207326 if (write_ddl_log && log_ddl != nullptr) {
5575 /* Write ddl log when space->prevent_file_open is true
5576 can cause deadlock:
5577 a. buffer flush thread waits for rename thread to set
5578 prevent_file_open to false;
5579 b. rename thread waits for buffer flush thread to flush
5580 a page and release page lock. The page is ready for
5581 flush in double write buffer. */
5582
5583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103577 times.
103577 ut_ad(!space->prevent_file_open);
5584
5585 103577 file = &space->files.front();
5586
5587 char *new_file_name = new_path_in == nullptr
5588
2/12
✗ Branch 0 not taken.
✓ Branch 1 taken 103577 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 103577 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
207154 ? Fil_path::make_ibd_from_table_name(new_name)
5589
2/4
✓ Branch 0 taken 103577 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103577 times.
103577 : mem_strdup(new_path_in);
5590
5591 103577 char *old_file_name = file->name;
5592
5593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103577 times.
103577 ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != nullptr);
5594
5595
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103577 times.
103577 ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != nullptr);
5596
5597
1/2
✓ Branch 0 taken 103577 times.
✗ Branch 1 not taken.
103577 mutex_release();
5598
5599 /* Rename ddl log is for rollback, so we exchange
5600 old file name with new file name. */
5601
1/2
✓ Branch 0 taken 103420 times.
✗ Branch 1 not taken.
103577 dberr_t err = log_ddl->write_rename_space_log(space_id, new_file_name,
5602 old_file_name);
5603 103420 ut::free(new_file_name);
5604
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 103418 times.
103420 if (err != DB_SUCCESS) {
5605 2 return err;
5606 }
5607
5608 103418 write_ddl_log = false;
5609 103418 continue;
5610 103418 }
5611 #endif /* !UNIV_HOTBACKUP */
5612
5613 /* We temporarily close the .ibd file because we do
5614 not trust that operating systems can rename an open
5615 file. For the closing we have to wait until there
5616 are no pending I/O's or flushes on the file. */
5617
5618 103749 space->prevent_file_open = true;
5619
5620 103749 file = &space->files.front();
5621
5622
4/4
✓ Branch 0 taken 103737 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 103569 times.
✓ Branch 3 taken 168 times.
103749 if (file->n_pending_ios > 0 || file->n_pending_flushes > 0 ||
5623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103569 times.
103569 file->is_being_extended) {
5624 /* There are pending I/O's or flushes or the
5625 file is currently being extended, sleep for
5626 a while and retry */
5627
5628 180 retry = true;
5629
5630 180 space->prevent_file_open = false;
5631
5632
3/4
✓ Branch 0 taken 103569 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 151 times.
✓ Branch 3 taken 103418 times.
103569 } else if (!file->is_flushed()) {
5633 /* Flush the space */
5634
5635 151 retry = flush = true;
5636
5637 151 space->prevent_file_open = false;
5638
5639
2/2
✓ Branch 0 taken 68361 times.
✓ Branch 1 taken 35057 times.
103418 } else if (file->is_open) {
5640
1/2
✓ Branch 0 taken 68361 times.
✗ Branch 1 not taken.
68361 close_file(file);
5641 }
5642
5643
2/2
✓ Branch 0 taken 103418 times.
✓ Branch 1 taken 331 times.
103749 if (!retry) {
5644
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103418 times.
103418 ut_ad(space->prevent_file_open);
5645 }
5646
5647
1/2
✓ Branch 0 taken 103749 times.
✗ Branch 1 not taken.
103749 mutex_release();
5648
5649
2/2
✓ Branch 0 taken 103418 times.
✓ Branch 1 taken 331 times.
103749 if (!retry) {
5650 103418 break;
5651 }
5652
5653
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 std::this_thread::sleep_for(std::chrono::milliseconds(100));
5654
5655
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 180 times.
331 if (flush) {
5656
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 mutex_acquire();
5657
5658
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 space_flush(space->id);
5659
5660
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 mutex_release();
5661 }
5662 103749 }
5663
5664 #ifndef UNIV_HOTBACKUP
5665 /* Make sure we re not holding shard mutex. */
5666
2/4
✓ Branch 0 taken 103418 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103418 times.
103418 ut_ad(!mutex_owned());
5667
1/2
✓ Branch 0 taken 103418 times.
✗ Branch 1 not taken.
103418 Clone_notify notifier(Clone_notify::Type::SPACE_RENAME, space_id, false);
5668
5669
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 103416 times.
103418 if (notifier.failed()) {
5670
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_acquire();
5671 2 space->prevent_file_open = false;
5672
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_release();
5673
5674 2 return DB_ERROR;
5675 }
5676 #endif /* !UNIV_HOTBACKUP */
5677
5678 char *new_file_name;
5679
5680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103416 times.
103416 if (new_path_in == nullptr) {
5681 new_file_name = Fil_path::make_ibd_from_table_name(new_name);
5682 } else {
5683
1/2
✓ Branch 0 taken 103416 times.
✗ Branch 1 not taken.
103416 new_file_name = mem_strdup(new_path_in);
5684 }
5685
5686 103416 char *old_file_name = file->name;
5687 103416 char *old_space_name = space->name;
5688
1/2
✓ Branch 0 taken 103416 times.
✗ Branch 1 not taken.
103416 char *new_space_name = mem_strdup(new_name);
5689
5690 #ifndef UNIV_HOTBACKUP
5691
1/2
✓ Branch 0 taken 103416 times.
✗ Branch 1 not taken.
103416 if (!recv_recovery_on) {
5692
1/2
✓ Branch 0 taken 103416 times.
✗ Branch 1 not taken.
103416 mtr_t mtr;
5693
5694
1/2
✓ Branch 0 taken 103416 times.
✗ Branch 1 not taken.
103416 mtr.start();
5695
5696
1/2
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
103416 fil_name_write_rename(space_id, old_file_name, new_file_name, &mtr);
5697
5698
1/2
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
103415 mtr.commit();
5699 103415 }
5700 #endif /* !UNIV_HOTBACKUP */
5701
5702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103415 times.
103415 ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != nullptr);
5703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103415 times.
103415 ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != nullptr);
5704
5705
1/2
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
103415 mutex_acquire();
5706
5707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103415 times.
103415 ut_ad(space->prevent_file_open);
5708
5709 /* We already checked these. */
5710
2/4
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103415 times.
103415 ut_ad(space == get_space_by_name(old_space_name));
5711
2/4
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103415 times.
103415 ut_ad(get_space_by_name(new_space_name) == nullptr);
5712
5713 bool success;
5714
5715
3/4
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 103414 times.
103415 DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", goto skip_rename;);
5716
5717
2/6
✓ Branch 0 taken 103414 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103414 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
103414 DBUG_INJECT_CRASH("ddl_crash_before_rename_tablespace",
5718 crash_injection_rename_tablespace_counter++);
5719
5720 103414 file = &space->files.front();
5721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103414 times.
103414 ut_ad(!file->is_open);
5722
5723
1/2
✓ Branch 0 taken 103414 times.
✗ Branch 1 not taken.
103414 success = os_file_rename(innodb_data_file_key, old_file_name, new_file_name);
5724
5725
2/4
✓ Branch 0 taken 103414 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103414 times.
103415 DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", skip_rename
5726 : success = false;);
5727
5728
2/6
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 103415 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
103415 DBUG_INJECT_CRASH("ddl_crash_after_rename_tablespace",
5729 crash_injection_rename_tablespace_counter++);
5730
5731
2/2
✓ Branch 0 taken 103414 times.
✓ Branch 1 taken 1 times.
103415 if (success) {
5732 103414 file->name = new_file_name;
5733
5734
1/2
✓ Branch 0 taken 103414 times.
✗ Branch 1 not taken.
103414 update_space_name_map(space, new_space_name);
5735
5736 103414 space->name = new_space_name;
5737
5738 } else {
5739 /* Because nothing was renamed, we must free the new
5740 names, not the old ones. */
5741 1 old_file_name = new_file_name;
5742 1 old_space_name = new_space_name;
5743 }
5744
5745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103415 times.
103415 ut_ad(space->prevent_file_open);
5746 103415 space->prevent_file_open = false;
5747
5748
1/2
✓ Branch 0 taken 103415 times.
✗ Branch 1 not taken.
103415 mutex_release();
5749
5750 103415 ut::free(old_file_name);
5751 103415 ut::free(old_space_name);
5752
5753
2/2
✓ Branch 0 taken 103414 times.
✓ Branch 1 taken 1 times.
103415 return success ? DB_SUCCESS : DB_ERROR;
5754 103417 }
5755
5756 /** Rename a single-table tablespace.
5757 The tablespace must exist in the memory cache.
5758 @param[in] space_id Tablespace ID
5759 @param[in] old_path Old file name
5760 @param[in] new_name New tablespace name in the schema/name format
5761 @param[in] new_path_in New file name, or nullptr if it is located in
5762 the normal data directory
5763 @return InnoDB error code */
5764 103578 dberr_t fil_rename_tablespace(space_id_t space_id, const char *old_path,
5765 const char *new_name, const char *new_path_in) {
5766 103578 auto shard = fil_system->shard_by_id(space_id);
5767
5768 103578 dberr_t err = shard->space_rename(space_id, old_path, new_name, new_path_in);
5769
5770 103420 return err;
5771 }
5772
5773 /** Rename a tablespace. Use the space_id to find the shard.
5774 @param[in] space_id tablespace ID
5775 @param[in] old_name old tablespace name
5776 @param[in] new_name new tablespace name
5777 @return DB_SUCCESS on success */
5778 74 dberr_t Fil_system::rename_tablespace_name(space_id_t space_id,
5779 const char *old_name,
5780 const char *new_name) {
5781 74 auto old_shard = fil_system->shard_by_id(space_id);
5782
5783 74 old_shard->mutex_acquire();
5784
5785 74 auto old_space = old_shard->get_space_by_id(space_id);
5786
5787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (old_space == nullptr) {
5788 old_shard->mutex_release();
5789
5790 ib::error(ER_IB_MSG_299, old_name);
5791
5792 return DB_TABLESPACE_NOT_FOUND;
5793 }
5794
5795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 ut_ad(old_space == old_shard->get_space_by_name(old_name));
5796 74 old_shard->mutex_release();
5797
5798 74 Fil_shard *new_shard{};
5799 74 fil_space_t *new_space{};
5800
5801 74 mutex_acquire_all();
5802
5803
2/2
✓ Branch 0 taken 5032 times.
✓ Branch 1 taken 74 times.
5106 for (auto shard : m_shards) {
5804
1/2
✓ Branch 0 taken 5032 times.
✗ Branch 1 not taken.
5032 new_space = shard->get_space_by_name(new_name);
5805
5806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5032 times.
5032 if (new_space != nullptr) {
5807 new_shard = shard;
5808 break;
5809 }
5810 }
5811
5812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (new_space != nullptr) {
5813 mutex_release_all();
5814
5815 if (new_space->id != old_space->id) {
5816 ib::error(ER_IB_MSG_300, new_name);
5817
5818 return DB_TABLESPACE_EXISTS;
5819 } else {
5820 ut_a(new_shard == old_shard);
5821 }
5822
5823 return DB_SUCCESS;
5824 }
5825
5826 74 auto new_space_name = mem_strdup(new_name);
5827 74 auto old_space_name = old_space->name;
5828
5829 74 old_shard->update_space_name_map(old_space, new_space_name);
5830
5831 74 old_space->name = new_space_name;
5832
5833 74 mutex_release_all();
5834
5835 74 ut::free(old_space_name);
5836
5837 74 return DB_SUCCESS;
5838 }
5839
5840 74 dberr_t fil_rename_tablespace_by_id(space_id_t space_id, const char *old_name,
5841 const char *new_name) {
5842 74 return fil_system->rename_tablespace_name(space_id, old_name, new_name);
5843 }
5844
5845 315781 dberr_t fil_write_initial_pages(pfs_os_file_t file, const char *path,
5846 fil_type_t type [[maybe_unused]],
5847 page_no_t size, const byte *encrypt_info,
5848 space_id_t space_id, uint32_t &space_flags,
5849 bool &atomic_write, bool &punch_hole) {
5850 315781 bool success = false;
5851 315781 atomic_write = false;
5852 315781 punch_hole = false;
5853
5854
1/2
✓ Branch 0 taken 315781 times.
✗ Branch 1 not taken.
315781 const page_size_t page_size(space_flags);
5855
1/2
✓ Branch 0 taken 315781 times.
✗ Branch 1 not taken.
315781 const auto sz = ulonglong{size * page_size.physical()};
5856
5857 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
5858 {
5859 315781 int ret = 0;
5860 #ifdef UNIV_DEBUG
5861
3/4
✓ Branch 0 taken 315781 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 315771 times.
315781 DBUG_EXECUTE_IF("fil_create_temp_tablespace_fail_fallocate", ret = -1;);
5862
2/2
✓ Branch 0 taken 315771 times.
✓ Branch 1 taken 10 times.
315781 if (ret == 0)
5863 #endif /* UNIV_DEBUG */
5864 {
5865
1/2
✓ Branch 0 taken 315771 times.
✗ Branch 1 not taken.
315771 ret = posix_fallocate(file.m_file, 0, sz);
5866 }
5867
5868
2/2
✓ Branch 0 taken 315771 times.
✓ Branch 1 taken 10 times.
315781 if (ret == 0) {
5869 315771 success = true;
5870
4/4
✓ Branch 0 taken 196131 times.
✓ Branch 1 taken 119640 times.
✓ Branch 2 taken 119640 times.
✓ Branch 3 taken 196131 times.
511902 if (type == FIL_TYPE_TEMPORARY ||
5871
2/4
✓ Branch 0 taken 196131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 196131 times.
196131 fil_fusionio_enable_atomic_write(file)) {
5872 119640 atomic_write = true;
5873 }
5874 } else {
5875 /* If posix_fallocate() fails for any reason, issue only a warning
5876 and then fall back to os_file_set_size() */
5877
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 ib::warn(ER_IB_MSG_303, path, sz, ret, strerror(errno));
5878 }
5879 }
5880 #endif /* !NO_FALLOCATE && UNIV_LINUX */
5881
5882
6/6
✓ Branch 0 taken 315771 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 315738 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 196128 times.
✓ Branch 5 taken 119610 times.
315781 if (!success || (tbsp_extend_and_initialize && !atomic_write)) {
5883
1/2
✓ Branch 0 taken 196135 times.
✗ Branch 1 not taken.
196138 success = os_file_set_size(path, file, 0, sz, true);
5884
5885
1/2
✓ Branch 0 taken 196135 times.
✗ Branch 1 not taken.
196135 if (success) {
5886 /* explicit initialization is needed as same as fil_space_extend(),
5887 instead of punch_hole. */
5888 dberr_t err =
5889
2/4
✓ Branch 0 taken 196136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 196138 times.
✗ Branch 3 not taken.
196135 os_file_write_zeros(file, path, page_size.physical(), 0, sz);
5890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196138 times.
196138 if (err != DB_SUCCESS) {
5891 ib::warn(ER_IB_MSG_320) << "Error while writing " << sz << " zeroes to "
5892 << path << " starting at offset " << 0;
5893 }
5894 }
5895 }
5896
5897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315781 times.
315781 if (!success) {
5898 return DB_OUT_OF_DISK_SPACE;
5899 }
5900
5901 /* Note: We are actually punching a hole, previous contents will
5902 be lost after this call, if it succeeds. In this case the file
5903 should be full of NULs. */
5904
5905
1/2
✓ Branch 0 taken 315781 times.
✗ Branch 1 not taken.
315781 punch_hole = os_is_sparse_file_supported(file);
5906
5907 /* Should not make large punch hole as initialization of large file,
5908 for crash-recovery safeness around disk-full. */
5909
5910 /* We have to write the space id to the file immediately and flush the
5911 file to disk. This is because in crash recovery we must be aware what
5912 tablespaces exist and what are their space id's, so that we can apply
5913 the log records to the right file. It may take quite a while until
5914 buffer pool flush algorithms write anything to the file and flush it to
5915 disk. If we would not write here anything, the file would be filled
5916 with zeros from the call of os_file_set_size(), until a buffer pool
5917 flush would write to it. */
5918
5919 /* Align the memory for file i/o if we might have O_DIRECT set */
5920 auto page = static_cast<byte *>(
5921
2/4
✓ Branch 0 taken 315780 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 315780 times.
✗ Branch 3 not taken.
315781 ut::aligned_zalloc(2 * page_size.logical(), page_size.logical()));
5922
5923 /* Add the UNIV_PAGE_SIZE to the table flags and write them to the
5924 tablespace header. */
5925
1/2
✓ Branch 0 taken 315780 times.
✗ Branch 1 not taken.
315780 space_flags = fsp_flags_set_page_size(space_flags, page_size);
5926
1/2
✓ Branch 0 taken 315780 times.
✗ Branch 1 not taken.
315780 fsp_header_init_fields(page, space_id, space_flags);
5927
1/2
✓ Branch 0 taken 315778 times.
✗ Branch 1 not taken.
315780 mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
5928
5929
1/2
✓ Branch 0 taken 315779 times.
✗ Branch 1 not taken.
315778 mach_write_to_4(page + FIL_PAGE_SRV_VERSION, DD_SPACE_CURRENT_SRV_VERSION);
5930
1/2
✓ Branch 0 taken 315779 times.
✗ Branch 1 not taken.
315779 mach_write_to_4(page + FIL_PAGE_SPACE_VERSION,
5931 DD_SPACE_CURRENT_SPACE_VERSION);
5932
5933
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 315743 times.
315779 if (encrypt_info != nullptr) {
5934
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 auto key_offset = fsp_header_get_encryption_offset(page_size);
5935 36 memcpy(page + key_offset, encrypt_info, Encryption::INFO_SIZE);
5936 }
5937
5938
1/2
✓ Branch 0 taken 315780 times.
✗ Branch 1 not taken.
315779 IORequest request(IORequest::WRITE);
5939 315780 dberr_t err = DB_SUCCESS;
5940
5941
2/2
✓ Branch 0 taken 314844 times.
✓ Branch 1 taken 935 times.
315780 if (!page_size.is_compressed()) {
5942 314846 buf_flush_init_for_writing(nullptr, page, nullptr, 0,
5943
2/4
✓ Branch 0 taken 314846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 314846 times.
✗ Branch 3 not taken.
314844 fsp_is_checksum_disabled(space_id),
5944 true /* skip_lsn_check */);
5945
5946
2/4
✓ Branch 0 taken 314846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 314846 times.
✗ Branch 3 not taken.
314846 err = os_file_write(request, path, file, page, 0, page_size.physical());
5947
5948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 314846 times.
314846 ut_ad(err != DB_IO_NO_PUNCH_HOLE);
5949
5950 } else {
5951 page_zip_des_t page_zip;
5952
5953
2/4
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 935 times.
✗ Branch 3 not taken.
935 page_zip_set_size(&page_zip, page_size.physical());
5954
1/2
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
935 page_zip.data = page + page_size.logical();
5955 935 ut_d(page_zip.m_start = 0);
5956 935 page_zip.m_end = 0;
5957 935 page_zip.n_blobs = 0;
5958 935 page_zip.m_nonempty = false;
5959
5960 935 buf_flush_init_for_writing(nullptr, page, &page_zip, 0,
5961
2/4
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 935 times.
✗ Branch 3 not taken.
935 fsp_is_checksum_disabled(space_id),
5962 true /* skip_lsn_check */);
5963
5964
2/4
✓ Branch 0 taken 935 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 935 times.
✗ Branch 3 not taken.
935 err = os_file_write(request, path, file, page_zip.data, 0,
5965 page_size.physical());
5966
5967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 935 times.
935 ut_a(err != DB_IO_NO_PUNCH_HOLE);
5968
5969 935 punch_hole = false;
5970 }
5971
5972 315781 ut::aligned_free(page);
5973 315781 return err;
5974 315781 }
5975
5976 /** Create a tablespace (an IBD or IBT) file
5977 @param[in] space_id Tablespace ID
5978 @param[in] name Tablespace name in dbname/tablename format.
5979 For general tablespaces, the 'dbname/' part
5980 may be missing.
5981 @param[in] path Path and filename of the datafile to create.
5982 @param[in] flags Tablespace flags
5983 @param[in] size Initial size of the tablespace file in pages,
5984 must be >= FIL_IBD_FILE_INITIAL_SIZE
5985 @param[in] type FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY
5986 @param[in] mode keyring encryption mode
5987 @param[in] keyring_encryption_key_id info on keyring encryption key
5988 @return DB_SUCCESS or error code */
5989 315380 static dberr_t fil_create_tablespace(
5990 space_id_t space_id, const char *name, const char *path, uint32_t flags,
5991 page_no_t size, fil_type_t type, const fil_encryption_t mode,
5992 const KeyringEncryptionKeyIdInfo &keyring_encryption_key_id) {
5993 315380 fil_space_crypt_t *crypt_data = nullptr;
5994
5995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315380 times.
315380 ut_ad(!fsp_is_system_tablespace(space_id));
5996
2/4
✓ Branch 0 taken 315380 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 315380 times.
315380 ut_a(fsp_flags_is_valid(flags));
5997
4/6
✓ Branch 0 taken 195730 times.
✓ Branch 1 taken 119650 times.
✓ Branch 2 taken 195730 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 315380 times.
315380 ut_a(type == FIL_TYPE_TEMPORARY || type == FIL_TYPE_TABLESPACE);
5998
5999 315380 bool has_shared_space = FSP_FLAGS_GET_SHARED(flags);
6000 /* Create the subdirectories in the path, if they are
6001 not there already. */
6002
2/2
✓ Branch 0 taken 194464 times.
✓ Branch 1 taken 120916 times.
315380 if (!has_shared_space) {
6003
1/2
✓ Branch 0 taken 194464 times.
✗ Branch 1 not taken.
194464 auto err = os_file_create_subdirs_if_needed(path);
6004
6005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 194464 times.
194464 if (err != DB_SUCCESS) {
6006 return err; /* purecov: inspected */
6007 }
6008 }
6009
6010 315380 bool success = false;
6011
6012
6/8
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 314960 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 420 times.
✓ Branch 4 taken 119650 times.
✓ Branch 5 taken 195730 times.
✓ Branch 6 taken 315380 times.
✗ Branch 7 not taken.
315380 auto file = os_file_create(
6013 type == FIL_TYPE_TEMPORARY ? innodb_temp_file_key : innodb_data_file_key,
6014 path, OS_FILE_CREATE | OS_FILE_ON_ERROR_NO_EXIT, OS_FILE_NORMAL,
6015 OS_DATA_FILE, srv_read_only_mode && (type != FIL_TYPE_TEMPORARY),
6016 &success);
6017
6018
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 315373 times.
315380 if (!success) {
6019 /* purecov: begin inspected */
6020 /* The following call will print an error message */
6021
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ulint error = os_file_get_last_error(true);
6022
6023
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ib::error(ER_IB_MSG_301, path);
6024
6025
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 switch (error) {
6026 case OS_FILE_ALREADY_EXISTS:
6027 #ifndef UNIV_HOTBACKUP
6028 ib::error(ER_IB_MSG_UNEXPECTED_FILE_EXISTS, path, path);
6029 return DB_TABLESPACE_EXISTS;
6030 #else /* !UNIV_HOTBACKUP */
6031 return DB_SUCCESS; /* Already existing file not an error here. */
6032 #endif /* !UNIV_HOTBACKUP */
6033
6034 case OS_FILE_NAME_TOO_LONG:
6035 ib::error(ER_IB_MSG_TOO_LONG_PATH, path);
6036 return DB_TOO_LONG_PATH;
6037
6038 case OS_FILE_DISK_FULL:
6039 return DB_OUT_OF_DISK_SPACE;
6040
6041 7 default:
6042 7 return DB_ERROR;
6043 }
6044 /* purecov: end */
6045 }
6046
6047 315373 bool atomic_write = false;
6048 315373 bool punch_hole = false;
6049
6050
1/2
✓ Branch 0 taken 315372 times.
✗ Branch 1 not taken.
315373 auto err = fil_write_initial_pages(file, path, type, size, nullptr, space_id,
6051 flags, atomic_write, punch_hole);
6052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315372 times.
315372 if (err != DB_SUCCESS) {
6053 ib::error(ER_IB_MSG_304, path);
6054
6055 os_file_close(file);
6056 os_file_delete(innodb_data_file_key, path);
6057
6058 return err;
6059 }
6060
6061
1/2
✓ Branch 0 taken 315371 times.
✗ Branch 1 not taken.
315372 success = os_file_flush(file);
6062
6063
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315371 times.
315371 if (!success) {
6064 ib::error(ER_IB_MSG_305, path);
6065
6066 os_file_close(file);
6067 os_file_delete(innodb_data_file_key, path);
6068 return DB_ERROR;
6069 }
6070
6071 #ifndef UNIV_HOTBACKUP
6072 /* Notifier block covers space creation and initialization. */
6073
1/2
✓ Branch 0 taken 315373 times.
✗ Branch 1 not taken.
630743 Clone_notify notifier(Clone_notify::Type::SPACE_CREATE, space_id, false);
6074
6075
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 315369 times.
315373 if (notifier.failed()) {
6076
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 os_file_close(file);
6077
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 fil_space_destroy_crypt_data(&crypt_data);
6078 4 return DB_ERROR;
6079 }
6080 #endif /* !UNIV_HOTBACKUP */
6081
6082
1/2
✓ Branch 0 taken 315369 times.
✗ Branch 1 not taken.
315369 auto space = fil_space_create(name, space_id, flags, type, crypt_data, mode);
6083
6084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315369 times.
315369 if (space == nullptr) {
6085 os_file_close(file);
6086 os_file_delete(innodb_data_file_key, path);
6087
6088 return DB_ERROR;
6089 }
6090
6091
3/4
✓ Branch 0 taken 308960 times.
✓ Branch 1 taken 6409 times.
✓ Branch 2 taken 308960 times.
✗ Branch 3 not taken.
315369 DEBUG_SYNC_C("fil_ibd_created_space");
6092
6093
1/2
✓ Branch 0 taken 315369 times.
✗ Branch 1 not taken.
315369 auto shard = fil_system->shard_by_id(space_id);
6094
6095 fil_node_t *file_node =
6096
1/2
✓ Branch 0 taken 315369 times.
✗ Branch 1 not taken.
315369 shard->create_node(path, size, space, false, punch_hole, atomic_write);
6097
6098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315369 times.
315369 err = (file_node == nullptr) ? DB_ERROR : DB_SUCCESS;
6099
6100 #ifndef UNIV_HOTBACKUP
6101 /* Temporary tablespace creation need not be redo logged */
6102
3/4
✓ Branch 0 taken 315369 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 195719 times.
✓ Branch 3 taken 119650 times.
315369 if (err == DB_SUCCESS && type != FIL_TYPE_TEMPORARY) {
6103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195719 times.
195719 ut_a(space->files.size() == 1);
6104 195719 const auto &file = space->files.front();
6105
6106
1/2
✓ Branch 0 taken 195719 times.
✗ Branch 1 not taken.
195719 mtr_t mtr;
6107
6108
1/2
✓ Branch 0 taken 195718 times.
✗ Branch 1 not taken.
195719 mtr_start(&mtr);
6109
6110
1/2
✓ Branch 0 taken 195716 times.
✗ Branch 1 not taken.
195718 fil_op_write_log(MLOG_FILE_CREATE, space_id, file.name, nullptr,
6111 space->flags, &mtr);
6112
6113
1/2
✓ Branch 0 taken 195718 times.
✗ Branch 1 not taken.
195716 mtr_commit(&mtr);
6114
6115
4/6
✓ Branch 0 taken 195719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 195718 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
195718 DBUG_EXECUTE_IF("fil_ibd_create_log", log_make_latest_checkpoint(););
6116 195719 }
6117
6118 #endif /* !UNIV_HOTBACKUP */
6119
6120 /* For encryption tablespace, initial encryption information. */
6121
5/6
✓ Branch 0 taken 315369 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4699 times.
✓ Branch 3 taken 310669 times.
✓ Branch 4 taken 4699 times.
✓ Branch 5 taken 310669 times.
630737 if (space != nullptr &&
6122 315369 (FSP_FLAGS_GET_ENCRYPTION(space->flags))) {
6123
1/2
✓ Branch 0 taken 4699 times.
✗ Branch 1 not taken.
4699 err = fil_set_encryption(
6124 space->id,
6125 Encryption::AES, nullptr,
6126 nullptr);
6127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4699 times.
4699 ut_ad(err == DB_SUCCESS);
6128 }
6129
6130 315368 space->encryption_op_in_progress = Encryption::Progress::NONE;
6131
6132
1/2
✓ Branch 0 taken 315368 times.
✗ Branch 1 not taken.
315368 os_file_close(file);
6133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315368 times.
315368 if (err != DB_SUCCESS) {
6134 os_file_delete(innodb_data_file_key, path);
6135 }
6136
6137 315368 return err;
6138 }
6139
6140 195730 dberr_t fil_ibd_create(
6141 space_id_t space_id, const char *name, const char *path, uint32_t flags,
6142 page_no_t size, const fil_encryption_t mode,
6143 const KeyringEncryptionKeyIdInfo &keyring_encryption_key_id) {
6144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195730 times.
195730 ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
6145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195730 times.
195730 ut_ad(!srv_read_only_mode);
6146 195730 return fil_create_tablespace(space_id, name, path, flags, size,
6147 FIL_TYPE_TABLESPACE, mode,
6148 195730 keyring_encryption_key_id);
6149 }
6150
6151 119650 dberr_t fil_ibt_create(space_id_t space_id, const char *name, const char *path,
6152 uint32_t flags, page_no_t size) {
6153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119650 times.
119650 ut_a(size >= FIL_IBT_FILE_INITIAL_SIZE);
6154
1/2
✓ Branch 0 taken 119650 times.
✗ Branch 1 not taken.
119650 return fil_create_tablespace(space_id, name, path, flags, size,
6155 FIL_TYPE_TEMPORARY, FIL_ENCRYPTION_DEFAULT,
6156 239300 KeyringEncryptionKeyIdInfo());
6157 }
6158
6159 #ifndef UNIV_HOTBACKUP
6160 80454 dberr_t fil_ibd_open(bool validate, fil_type_t purpose, space_id_t space_id,
6161 uint32_t flags, const char *space_name,
6162 const char *path_in, bool strict, bool old_space,
6163 Keyring_encryption_info &keyring_encryption_info) {
6164 80454 Datafile df;
6165 80454 bool is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags);
6166 80454 bool for_import = (purpose == FIL_TYPE_IMPORT);
6167
6168
3/4
✓ Branch 0 taken 80454 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 80452 times.
80454 if (!fsp_flags_is_valid(flags)) {
6169 2 return DB_CORRUPTION;
6170 }
6171
6172 /* Check if the file is already open. The space can be loaded
6173 via fil_space_get_first_path() on startup. This is a problem
6174 for partitioning code. It's a convoluted call graph via the DD.
6175 On Windows this can lead to a sharing violation when we attempt
6176 to open it again. */
6177
6178
1/2
✓ Branch 0 taken 80452 times.
✗ Branch 1 not taken.
80452 auto shard = fil_system->shard_by_id(space_id);
6179
6180
1/2
✓ Branch 0 taken 80452 times.
✗ Branch 1 not taken.
80452 shard->mutex_acquire();
6181
6182
1/2
✓ Branch 0 taken 80452 times.
✗ Branch 1 not taken.
80452 auto space = shard->get_space_by_id(space_id);
6183
6184
1/2
✓ Branch 0 taken 80452 times.
✗ Branch 1 not taken.
80452 shard->mutex_release();
6185
6186
1/2
✓ Branch 0 taken 80452 times.
✗ Branch 1 not taken.
80452 df.init(space_name, flags);
6187
6188
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 80284 times.
80452 if (path_in == nullptr) {
6189
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 df.make_filepath(nullptr, space_name, IBD);
6190 } else {
6191
1/2
✓ Branch 0 taken 80284 times.
✗ Branch 1 not taken.
80284 df.set_filepath(path_in);
6192 }
6193
6194 /* Attempt to open the tablespace. */
6195
3/4
✓ Branch 0 taken 80452 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 80424 times.
✓ Branch 3 taken 28 times.
80452 if (df.open_read_only(strict) == DB_SUCCESS) {
6196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80424 times.
80424 ut_ad(df.is_open());
6197 } else {
6198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 ut_ad(!df.is_open());
6199 28 return DB_CANNOT_OPEN_FILE;
6200 }
6201
6202 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
6203 const bool atomic_write =
6204
5/8
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 79988 times.
✓ Branch 2 taken 436 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 436 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 436 times.
80424 !dblwr::is_enabled() && fil_fusionio_enable_atomic_write(df.handle());
6205 #else
6206 const bool atomic_write = false;
6207 #endif /* !NO_FALLOCATE && UNIV_LINUX */
6208
6209 80424 Datafile::ValidateOutput validate_output;
6210
6211
6/6
✓ Branch 0 taken 57708 times.
✓ Branch 1 taken 22716 times.
✓ Branch 2 taken 1980 times.
✓ Branch 3 taken 55728 times.
✓ Branch 4 taken 447 times.
✓ Branch 5 taken 79977 times.
105120 if ((validate || is_encrypted) &&
6212
1/2
✓ Branch 0 taken 24696 times.
✗ Branch 1 not taken.
24696 (validate_output = df.validate_to_dd(space_id, flags, for_import))
6213
2/2
✓ Branch 0 taken 447 times.
✓ Branch 1 taken 24249 times.
24696 .error != DB_SUCCESS) {
6214 /* We don't reply the rename via the redo log anymore.
6215 Therefore we can get a space ID mismatch when validating
6216 the files during bootstrap. */
6217
6218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 447 times.
447 if (validate_output.keyring_encryption_info.page0_has_crypt_data)
6219 keyring_encryption_info = validate_output.keyring_encryption_info;
6220
6221
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 421 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
447 if (!is_encrypted && validate_output.error != DB_WRONG_FILE_NAME) {
6222 /* The following call prints an error message.
6223 For encrypted tablespace we skip print, since it should
6224 be keyring plugin issues. */
6225
6226 os_file_get_last_error(true);
6227
6228 ib::error(ER_IB_MSG_306, space_name, TROUBLESHOOT_DATADICT_MSG);
6229 }
6230
6231 447 return validate_output.error;
6232 }
6233
6234
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 79976 times.
79977 if (validate_output.keyring_encryption_info.page0_has_crypt_data)
6235 1 keyring_encryption_info = validate_output.keyring_encryption_info;
6236
6237
6/6
✓ Branch 0 taken 22509 times.
✓ Branch 1 taken 57468 times.
✓ Branch 2 taken 22341 times.
✓ Branch 3 taken 168 times.
✓ Branch 4 taken 21726 times.
✓ Branch 5 taken 615 times.
79977 if (validate && !old_space && !for_import) {
6238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21726 times.
21726 if (df.server_version() > DD_SPACE_CURRENT_SRV_VERSION) {
6239 ib::error(ER_IB_MSG_1272, ulong{DD_SPACE_CURRENT_SRV_VERSION},
6240 ulonglong{df.server_version()});
6241 /* Server version is less than the tablespace server version.
6242 We don't support downgrade for 8.0 server, so report error */
6243 return DB_SERVER_VERSION_LOW;
6244 }
6245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21726 times.
21726 ut_ad(df.space_version() == DD_SPACE_CURRENT_SPACE_VERSION);
6246 }
6247
6248 /* We are done validating. If the tablespace is already open,
6249 return success. */
6250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79977 times.
79977 if (space != nullptr) {
6251 return DB_SUCCESS;
6252 }
6253
6254 /* We pass UNINITIALIZED flags while we try to open DD tablespace. In that
6255 case, set the flags now based on what is read from disk.*/
6256
5/8
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 79844 times.
✓ Branch 2 taken 133 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 79977 times.
79977 if (FSP_FLAGS_ARE_NOT_SET(flags) && fsp_is_dd_tablespace(space_id)) {
6257 flags = df.flags();
6258 is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags);
6259 }
6260
6261 79977 fil_space_crypt_t *crypt_data = nullptr;
6262
6263 { // Read keyring encryption data
6264 79977 bool close_df = false;
6265 81971 auto guard = create_scope_guard([&close_df, &df]() {
6266
2/2
✓ Branch 0 taken 1994 times.
✓ Branch 1 taken 77983 times.
79977 if (close_df) df.close();
6267
1/2
✓ Branch 0 taken 79977 times.
✗ Branch 1 not taken.
79977 });
6268
6269
5/6
✓ Branch 0 taken 1994 times.
✓ Branch 1 taken 77983 times.
✓ Branch 2 taken 1994 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1994 times.
✓ Branch 5 taken 77983 times.
79977 if (is_encrypted && !df.is_open()) {
6270 // df.validate_to_dd closes df
6271
2/4
✓ Branch 0 taken 1994 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1994 times.
1994 if (df.open_read_only(strict) != DB_SUCCESS) {
6272 ut_ad(!df.is_open());
6273 return DB_CANNOT_OPEN_FILE;
6274 }
6275 1994 close_df = true;
6276 }
6277
6278
2/2
✓ Branch 0 taken 57722 times.
✓ Branch 1 taken 22255 times.
79977 const byte *first_page = df.is_open() ? df.get_first_page() : nullptr;
6279 79977 crypt_data = first_page
6280
4/6
✓ Branch 0 taken 1994 times.
✓ Branch 1 taken 77983 times.
✓ Branch 2 taken 1994 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1994 times.
✗ Branch 5 not taken.
79977 ? fil_space_read_crypt_data(page_size_t(flags), first_page)
6281 : nullptr;
6282
6283 79977 keyring_encryption_info.page0_has_crypt_data = crypt_data != nullptr;
6284 79977 keyring_encryption_info.is_mk_to_keyring_rotation =
6285
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 79977 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
79977 crypt_data != nullptr && crypt_data->encryption_rotation ==
6286 Encryption_rotation::MASTER_KEY_TO_KEYRING;
6287
1/2
✓ Branch 0 taken 79977 times.
✗ Branch 1 not taken.
79977 }
6288
6289
1/2
✓ Branch 0 taken 79977 times.
✗ Branch 1 not taken.
79977 space = fil_space_create(space_name, space_id, flags, purpose, crypt_data);
6290
6291
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 79975 times.
79977 if (space == nullptr) {
6292
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (crypt_data != nullptr) fil_space_destroy_crypt_data(&crypt_data);
6293 2 return DB_ERROR;
6294 }
6295
6296 /* We do not measure the size of the file, that is why
6297 we pass the 0 below */
6298
6299 const fil_node_t *file =
6300
1/2
✓ Branch 0 taken 79975 times.
✗ Branch 1 not taken.
79975 shard->create_node(df.filepath(), 0, space, false,
6301
1/2
✓ Branch 0 taken 79975 times.
✗ Branch 1 not taken.
79975 IORequest::is_punch_hole_supported(), atomic_write);
6302
6303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79975 times.
79975 if (file == nullptr) {
6304 return DB_ERROR;
6305 }
6306
6307 /* Set encryption operation in progress */
6308 79975 space->encryption_op_in_progress = df.m_encryption_op_in_progress;
6309
6310 /* It's possible during Encryption processing, space flag for encryption
6311 has been updated in ibd file but server crashed before DD flags are
6312 updated. Thus, consider ibd setting for encryption. */
6313
2/2
✓ Branch 0 taken 1999 times.
✓ Branch 1 taken 77976 times.
79975 if (FSP_FLAGS_GET_ENCRYPTION(df.flags())) {
6314 1999 fsp_flags_set_encryption(space->flags);
6315 } else {
6316 77976 fsp_flags_unset_encryption(space->flags);
6317 }
6318
6319 /* For encryption tablespace, initialize encryption information.*/
6320
8/8
✓ Branch 0 taken 77981 times.
✓ Branch 1 taken 1994 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 77976 times.
✓ Branch 4 taken 1884 times.
✓ Branch 5 taken 115 times.
✓ Branch 6 taken 1884 times.
✓ Branch 7 taken 78091 times.
81859 if ((is_encrypted || FSP_FLAGS_GET_ENCRYPTION(space->flags)) && !for_import &&
6321
1/2
✓ Branch 0 taken 1884 times.
✗ Branch 1 not taken.
1884 crypt_data == nullptr) {
6322 dberr_t err;
6323 1884 byte *iv = df.m_encryption_iv;
6324 1884 byte *key = df.m_encryption_key;
6325
6326
1/2
✓ Branch 0 taken 1884 times.
✗ Branch 1 not taken.
1884 err = fil_set_encryption(space->id, Encryption::AES, key, iv);
6327
6328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1884 times.
1884 if (err != DB_SUCCESS) {
6329 return DB_ERROR;
6330 }
6331
6332 /* If tablespace is encrypted with default master key and server has already
6333 started, rotate it now. */
6334
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1884 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1884 times.
1884 if (df.m_encryption_master_key_id == Encryption::DEFAULT_MASTER_KEY_ID &&
6335 /* There is no dependency on master thread but we are trying to check if
6336 server is in initial phase or not. */
6337 srv_master_thread_is_active()) {
6338 /* Reencrypt tablespace key */
6339 std::vector<space_id_t> sid;
6340 sid.push_back(space->id);
6341 fil_encryption_reencrypt(sid);
6342 }
6343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78091 times.
78091 } else if (crypt_data) {
6344 dberr_t err = fil_set_encryption(space->id, Encryption::KEYRING, nullptr,
6345 crypt_data->iv);
6346 if (err != DB_SUCCESS) {
6347 return (DB_ERROR);
6348 }
6349 }
6350
6351 79975 return DB_SUCCESS;
6352 80454 }
6353
6354 #else /* !UNIV_HOTBACKUP */
6355
6356 /** Allocates a file name for an old version of a single-table tablespace.
6357 The string must be freed by caller with ut::free()!
6358 @param[in] name Original file name
6359 @return own: file name */
6360 static char *meb_make_ibbackup_old_name(const char *name) {
6361 char *path;
6362 ulint len = strlen(name);
6363 static const char suffix[] = "_ibbackup_old_vers_";
6364
6365 path = static_cast<char *>(
6366 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, len + 15 + sizeof(suffix)));
6367
6368 memcpy(path, name, len);
6369 memcpy(path + len, suffix, sizeof(suffix) - 1);
6370
6371 meb_sprintf_timestamp_without_extra_chars(path + len + sizeof(suffix) - 1);
6372
6373 return path;
6374 }
6375 #endif /* UNIV_HOTBACKUP */
6376
6377 /** Looks for a pre-existing fil_space_t with the given tablespace ID
6378 and, if found, returns the name and filepath in newly allocated buffers
6379 that the caller must free.
6380 @param[in] space_id The tablespace ID to search for.
6381 @param[out] name Name of the tablespace found.
6382 @param[out] filepath The filepath of the first datafile for the
6383 tablespace.
6384 @return true if tablespace is found, false if not. */
6385 58447 bool fil_space_read_name_and_filepath(space_id_t space_id, char **name,
6386 char **filepath) {
6387 58447 bool success = false;
6388
6389 58447 *name = nullptr;
6390 58447 *filepath = nullptr;
6391
6392 58447 auto shard = fil_system->shard_by_id(space_id);
6393
6394 58447 shard->mutex_acquire();
6395
6396 58447 fil_space_t *space = shard->get_space_by_id(space_id);
6397
6398
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 58316 times.
58447 if (space != nullptr) {
6399 131 *name = mem_strdup(space->name);
6400
6401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 ut_a(space->files.size() == 1);
6402 131 *filepath = mem_strdup(space->files.front().name);
6403
6404 131 success = true;
6405 }
6406
6407 58447 shard->mutex_release();
6408
6409 58447 return success;
6410 }
6411
6412 /** Convert a file name to a tablespace name. Strip the file name
6413 prefix and suffix, leaving only databasename/tablename.
6414 @param[in] filename directory/databasename/tablename.ibd
6415 @return database/tablename string, to be freed with ut::free() */
6416 4728 char *fil_path_to_space_name(const char *filename) {
6417
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 std::string path{filename};
6418 4728 auto pos = path.find_last_of(Fil_path::SEPARATOR);
6419
6420
3/6
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4728 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4728 times.
4728 ut_a(pos != std::string::npos && !Fil_path::is_separator(path.back()));
6421
6422
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 std::string db_name = path.substr(0, pos);
6423
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 std::string space_name = path.substr(pos + 1, path.length());
6424
6425 /* If it is a path such as a/b/c.ibd, ignore everything before 'b'. */
6426 4728 pos = db_name.find_last_of(Fil_path::SEPARATOR);
6427
6428
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 if (pos != std::string::npos) {
6429
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 db_name = db_name.substr(pos + 1);
6430 }
6431
6432 char *name;
6433
6434
2/4
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4728 times.
✗ Branch 3 not taken.
4728 if (Fil_path::has_suffix(IBD, space_name)) {
6435 /* fil_space_t::name always uses '/' . */
6436
6437
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 path = db_name;
6438
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 path.push_back('/');
6439
6440 /* Strip the ".ibd" suffix. */
6441
2/4
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4728 times.
✗ Branch 3 not taken.
4728 path.append(space_name.substr(0, space_name.length() - 4));
6442
6443
1/2
✓ Branch 0 taken 4728 times.
✗ Branch 1 not taken.
4728 name = mem_strdupl(path.c_str(), path.length());
6444
6445 } else {
6446 /* Must have an "undo" prefix. */
6447 ut_ad(space_name.find("undo") == 0);
6448
6449 name = mem_strdupl(space_name.c_str(), space_name.length());
6450 }
6451
6452 4728 return name;
6453 4728 }
6454
6455 /** Open an ibd tablespace and add it to the InnoDB data structures.
6456 This is similar to fil_ibd_open() except that it is used while processing
6457 the redo and DDL log, so the data dictionary is not available and very little
6458 validation is done. The tablespace name is extracted from the
6459 dbname/tablename.ibd portion of the filename, which assumes that the file
6460 is a file-per-table tablespace. Any name will do for now. General
6461 tablespace names will be read from the dictionary after it has been
6462 recovered. The tablespace flags are read at this time from the first page
6463 of the file in validate_for_recovery().
6464 @param[in] space_id tablespace ID
6465 @param[in] path path/to/databasename/tablename.ibd
6466 @param[out] space the tablespace, or nullptr on error
6467 @return status of the operation */
6468 18601 fil_load_status Fil_shard::ibd_open_for_recovery(space_id_t space_id,
6469 const std::string &path,
6470 fil_space_t *&space) {
6471 /* If the a space is already in the file system cache with this
6472 space ID, then there is nothing to do. */
6473
6474
1/2
✓ Branch 0 taken 18601 times.
✗ Branch 1 not taken.
18601 mutex_acquire();
6475
6476
1/2
✓ Branch 0 taken 18601 times.
✗ Branch 1 not taken.
18601 space = get_space_by_id(space_id);
6477
6478
1/2
✓ Branch 0 taken 18601 times.
✗ Branch 1 not taken.
18601 mutex_release();
6479
6480 18601 const char *filename = path.c_str();
6481
6482
2/2
✓ Branch 0 taken 7900 times.
✓ Branch 1 taken 10701 times.
18601 if (space != nullptr) {
6483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7900 times.
7900 ut_a(space->files.size() == 1);
6484
6485 7900 const auto &file = space->files.front();
6486
6487 /* Compare the real paths. */
6488
4/8
✓ Branch 0 taken 7900 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7900 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7900 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7900 times.
✗ Branch 7 not taken.
7900 if (Fil_path::is_same_as(filename, file.name)) {
6489 7900 return FIL_LOAD_OK;
6490 }
6491
6492 #ifdef UNIV_HOTBACKUP
6493 ib::trace_2() << "Ignoring data file '" << filename << "' with space ID "
6494 << space->id << ". Another data file called '" << file.name
6495 << "' exists with the same space ID";
6496 #else /* UNIV_HOTBACKUP */
6497 ib::info(ER_IB_MSG_307, filename, ulong{space->id}, file.name);
6498 #endif /* UNIV_HOTBACKUP */
6499
6500 space = nullptr;
6501
6502 return FIL_LOAD_ID_CHANGED;
6503 }
6504
6505 10701 Datafile df;
6506
6507
1/2
✓ Branch 0 taken 10701 times.
✗ Branch 1 not taken.
10701 df.set_filepath(filename);
6508
6509
2/4
✓ Branch 0 taken 10701 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10701 times.
10701 if (df.open_read_only(false) != DB_SUCCESS) {
6510 return FIL_LOAD_NOT_FOUND;
6511 }
6512
6513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10701 times.
10701 ut_ad(df.is_open());
6514
6515 /* Get and test the file size. */
6516
2/4
✓ Branch 0 taken 10701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10701 times.
✗ Branch 3 not taken.
10701 os_offset_t size = os_file_get_size(df.handle());
6517
6518 /* Read and validate the first page of the tablespace. Assign a tablespace
6519 name based on the tablespace type. This will close the file, but will leave
6520 the flags and names to be queried. */
6521
1/2
✓ Branch 0 taken 10701 times.
✗ Branch 1 not taken.
10701 dberr_t err = df.validate_for_recovery(space_id).error;
6522
6523
4/8
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10697 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 10701 times.
10701 ut_a(err == DB_SUCCESS || err == DB_INVALID_ENCRYPTION_META ||
6524 err == DB_CORRUPTION);
6525
6526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10701 times.
10701 if (err == DB_CORRUPTION) {
6527 return FIL_LOAD_DBWLR_CORRUPTION;
6528 }
6529
6530
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10697 times.
10701 if (err == DB_INVALID_ENCRYPTION_META) {
6531
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 bool success = fil_system->erase_path(space_id);
6532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 ut_a(success);
6533 4 return FIL_LOAD_NOT_FOUND;
6534 }
6535
6536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 ut_a(df.space_id() == space_id);
6537
6538 /* Every .ibd file is created >= 4 pages in size.
6539 Smaller files cannot be OK. */
6540 os_offset_t minimum_size;
6541
6542 /* Every .ibd file is created >= FIL_IBD_FILE_INITIAL_SIZE
6543 pages in size. Smaller files cannot be OK. */
6544 {
6545
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 const page_size_t page_size(df.flags());
6546
6547
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 minimum_size = FIL_IBD_FILE_INITIAL_SIZE * page_size.physical();
6548 }
6549
6550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 if (size == static_cast<os_offset_t>(-1)) {
6551 /* The following call prints an error message */
6552 os_file_get_last_error(true);
6553
6554 ib::error(ER_IB_MSG_308) << "Could not measure the size of"
6555 " single-table tablespace file '"
6556 << df.filepath() << "'";
6557
6558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 } else if (size < minimum_size) {
6559 #ifndef UNIV_HOTBACKUP
6560 ib::error(ER_IB_MSG_309)
6561 << "The size of tablespace file '" << df.filepath() << "' is only "
6562 << size << ", should be at least " << minimum_size << "!";
6563 #else
6564 /* In MEB, we work around this error. */
6565 df.set_space_id(SPACE_UNKNOWN);
6566 df.set_flags(0);
6567 #endif /* !UNIV_HOTBACKUP */
6568 }
6569
6570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 ut_ad(space == nullptr);
6571
6572 #ifdef UNIV_HOTBACKUP
6573 if (df.space_id() == SPACE_UNKNOWN || df.space_id() == 0) {
6574 char *new_path;
6575
6576 ib::info(ER_IB_MSG_310)
6577 << "Renaming tablespace file '" << df.filepath() << "' with space ID "
6578 << df.space_id() << " to " << df.name()
6579 << "_ibbackup_old_vers_<timestamp>"
6580 " because its size "
6581 << df.size()
6582 << " is too small"
6583 " (< 4 pages 16 kB each), or the space id in the"
6584 " file header is not sensible. This can happen in"
6585 " an mysqlbackup run, and is not dangerous.";
6586 df.close();
6587
6588 new_path = meb_make_ibbackup_old_name(df.filepath());
6589
6590 bool success =
6591 os_file_rename(innodb_data_file_key, df.filepath(), new_path);
6592
6593 ut_a(success);
6594
6595 ut::free(new_path);
6596
6597 return FIL_LOAD_ID_CHANGED;
6598 }
6599
6600 /* A backup may contain the same space several times, if the space got
6601 renamed at a sensitive time. Since it is enough to have one version of
6602 the space, we rename the file if a space with the same space id
6603 already exists in the tablespace memory cache. We rather rename the
6604 file than delete it, because if there is a bug, we do not want to
6605 destroy valuable data. */
6606
6607 mutex_acquire();
6608
6609 space = get_space_by_id(space_id);
6610
6611 mutex_release();
6612
6613 if (space != nullptr) {
6614 ib::info(ER_IB_MSG_311)
6615 << "Renaming data file '" << df.filepath() << "' with space ID "
6616 << space_id << " to " << df.name()
6617 << "_ibbackup_old_vers_<timestamp> because space " << space->name
6618 << " with the same id was scanned"
6619 " earlier. This can happen if you have renamed tables"
6620 " during an mysqlbackup run.";
6621
6622 df.close();
6623
6624 char *new_path = meb_make_ibbackup_old_name(df.filepath());
6625
6626 bool success =
6627 os_file_rename(innodb_data_file_key, df.filepath(), new_path);
6628
6629 ut_a(success);
6630
6631 ut::free(new_path);
6632 return FIL_LOAD_OK;
6633 }
6634 #endif /* UNIV_HOTBACKUP */
6635
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 std::string tablespace_name(df.name());
6636
6637 /* During the apply-log operation, MEB already has translated the
6638 file name, so file name to space name conversion is not required. */
6639 #ifndef UNIV_HOTBACKUP
6640
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 dict_name::convert_to_space(tablespace_name);
6641 #endif /* !UNIV_HOTBACKUP */
6642
6643 10697 const byte *first_page = df.get_first_page();
6644 fil_space_crypt_t *crypt_data =
6645 first_page
6646
3/6
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10697 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10697 times.
✗ Branch 5 not taken.
10697 ? fil_space_read_crypt_data(page_size_t(df.flags()), first_page)
6647 10697 : nullptr;
6648
6649
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 fil_system->mutex_acquire_all();
6650
6651
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 space = space_create(tablespace_name.c_str(), space_id, df.flags(),
6652 FIL_TYPE_TABLESPACE, crypt_data);
6653
6654
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 fil_system->mutex_release_all();
6655
6656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 if (space == nullptr) {
6657 return FIL_LOAD_INVALID;
6658 }
6659
6660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 ut_ad(space->id == df.space_id());
6661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 ut_ad(space->id == space_id);
6662
6663 /* We do not use the size information we have about the file, because
6664 the rounding formula for extents and pages is somewhat complex; we
6665 let create_node() do that task. */
6666
6667 const fil_node_t *file;
6668
6669
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 file = create_node(df.filepath(), 0, space, false, true, false);
6670
6671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10697 times.
10697 ut_a(file != nullptr);
6672
6673 /* For encryption tablespace, initial encryption information. */
6674
4/4
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 10333 times.
✓ Branch 2 taken 264 times.
✓ Branch 3 taken 10433 times.
11061 if (FSP_FLAGS_GET_ENCRYPTION(space->flags) &&
6675
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 100 times.
364 df.m_encryption_key != nullptr) {
6676
1/2
✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
264 dberr_t err = fil_set_encryption(space->id, Encryption::AES,
6677 df.m_encryption_key, df.m_encryption_iv);
6678
6679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 264 times.
264 if (err != DB_SUCCESS) {
6680 ib::error(ER_IB_MSG_312, space->name);
6681 }
6682 }
6683
6684 /* Set encryption operation in progress */
6685 10697 space->encryption_op_in_progress = df.m_encryption_op_in_progress;
6686
1/2
✓ Branch 0 taken 10697 times.
✗ Branch 1 not taken.
10697 space->m_header_page_flush_lsn = df.get_flush_lsn();
6687
6688 10697 return FIL_LOAD_OK;
6689 10701 }
6690
6691 /** Open an ibd tablespace and add it to the InnoDB data structures.
6692 This is similar to fil_ibd_open() except that it is used while processing
6693 the redo log, so the data dictionary is not available and very little
6694 validation is done. The tablespace name is extracted from the
6695 dbname/tablename.ibd portion of the filename, which assumes that the file
6696 is a file-per-table tablespace. Any name will do for now. General
6697 tablespace names will be read from the dictionary after it has been
6698 recovered. The tablespace flags are read at this time from the first page
6699 of the file in validate_for_recovery().
6700 @param[in] space_id tablespace ID
6701 @param[in] path path/to/databasename/tablename.ibd
6702 @param[out] space the tablespace, or nullptr on error
6703 @return status of the operation */
6704 18609 fil_load_status Fil_system::ibd_open_for_recovery(space_id_t space_id,
6705 const std::string &path,
6706 fil_space_t *&space) {
6707 /* System tablespace open should never come here. It should be
6708 opened explicitly using the config path. */
6709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18609 times.
18609 ut_a(space_id != TRX_SYS_SPACE);
6710
6711 #ifndef UNIV_HOTBACKUP
6712 /* Do not attempt to open or load for recovery any undo tablespace that
6713 is currently being truncated. */
6714
4/4
✓ Branch 0 taken 4104 times.
✓ Branch 1 taken 14505 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 18601 times.
22713 if (fsp_is_undo_tablespace(space_id) &&
6715
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4096 times.
4104 undo::is_active_truncate_log_present(undo::id2num(space_id))) {
6716 8 return FIL_LOAD_NOT_FOUND;
6717 }
6718 #endif /* !UNIV_HOTBACKUP */
6719
6720 18601 auto shard = shard_by_id(space_id);
6721
6722 18601 return shard->ibd_open_for_recovery(space_id, path, space);
6723 }
6724
6725 #ifndef UNIV_HOTBACKUP
6726
6727 /** Report that a tablespace for a table was not found.
6728 @param[in] name Table name
6729 @param[in] space_id Table's space ID */
6730 static void fil_report_missing_tablespace(const char *name,
6731 space_id_t space_id) {
6732 ib::error(ER_IB_MSG_313)
6733 << "Table " << name << " in the InnoDB data dictionary has tablespace id "
6734 << space_id << ", but a tablespace with that id or name does not exist."
6735 << " Have you deleted or moved .ibd files?";
6736 }
6737
6738 1020908 bool Fil_shard::adjust_space_name(fil_space_t *space,
6739 const char *dd_space_name) {
6740
2/2
✓ Branch 0 taken 1019770 times.
✓ Branch 1 taken 1138 times.
1020908 if (!strcmp(space->name, dd_space_name)) {
6741 1019770 return true;
6742 }
6743
6744 bool replace_general =
6745
2/2
✓ Branch 0 taken 151 times.
✓ Branch 1 taken 987 times.
1289 FSP_FLAGS_GET_SHARED(space->flags) &&
6746
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 0 == strncmp(space->name, general_space_name, strlen(general_space_name));
6747 bool replace_undo =
6748
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 853 times.
1423 fsp_is_undo_tablespace(space->id) &&
6749
1/2
✓ Branch 0 taken 285 times.
✗ Branch 1 not taken.
285 0 == strncmp(space->name, undo_space_name, strlen(undo_space_name));
6750
6751 /* Update the auto-generated fil_space_t::name */
6752
4/4
✓ Branch 0 taken 987 times.
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 285 times.
✓ Branch 3 taken 702 times.
1138 if (replace_general || replace_undo) {
6753 436 char *old_space_name = space->name;
6754 436 char *new_space_name = mem_strdup(dd_space_name);
6755
6756 436 update_space_name_map(space, new_space_name);
6757
6758 436 space->name = new_space_name;
6759
6760 436 ut::free(old_space_name);
6761 }
6762
6763 /* Update the undo::Tablespace::name. Since the fil_shard mutex is held by
6764 the caller, it would be a sync order violation to get undo::spaces->s_lock.
6765 It is OK to skip this s_lock since this occurs during boot_tablespaces()
6766 which is still single threaded. */
6767
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 853 times.
1138 if (replace_undo) {
6768 285 space_id_t space_num = undo::id2num(space->id);
6769 285 undo::Tablespace *undo_space = undo::spaces->find(space_num);
6770 285 undo_space->set_space_name(dd_space_name);
6771 }
6772
6773
4/4
✓ Branch 0 taken 987 times.
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 285 times.
✓ Branch 3 taken 702 times.
1138 return (replace_general || replace_undo);
6774 }
6775
6776 1287763 bool Fil_shard::space_check_exists(space_id_t space_id, const char *name,
6777 bool print_err, bool adjust_space) {
6778 1287763 fil_space_t *fnamespace = nullptr;
6779
6780 1287763 mutex_acquire();
6781
6782 /* Look if there is a space with the same id */
6783 1287763 fil_space_t *space = get_space_by_id(space_id);
6784
6785 /* name is nullptr when replaying a DELETE ddl log. */
6786
2/2
✓ Branch 0 taken 196190 times.
✓ Branch 1 taken 1091573 times.
1287763 if (name == nullptr) {
6787 196190 mutex_release();
6788 196190 return (space != nullptr);
6789 }
6790
6791
2/2
✓ Branch 0 taken 1020908 times.
✓ Branch 1 taken 70665 times.
1091573 if (space != nullptr) {
6792 /* No need to check a general tablespace name if the DD
6793 is not yet available. */
6794
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1020908 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1020908 times.
1020908 if (!srv_sys_tablespaces_open && FSP_FLAGS_GET_SHARED(space->flags)) {
6795 mutex_release();
6796 return true;
6797 }
6798
6799 /* Sometimes the name has been auto-generated when the
6800 datafile is discovered and needs to be adjusted to that
6801 of the DD. This happens for general and undo tablespaces. */
6802
4/6
✓ Branch 0 taken 1020908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1020908 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1020206 times.
✓ Branch 5 taken 702 times.
2041816 if (srv_sys_tablespaces_open && adjust_space &&
6803
2/2
✓ Branch 0 taken 1020206 times.
✓ Branch 1 taken 702 times.
1020908 adjust_space_name(space, name)) {
6804 1020206 mutex_release();
6805 1020206 return true;
6806 }
6807
6808 /* If this space has the expected name, use it. */
6809 702 fnamespace = get_space_by_name(name);
6810
6811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 702 times.
702 if (space == fnamespace) {
6812 /* Found */
6813 mutex_release();
6814 return true;
6815 }
6816 }
6817
6818 /* Info from "fnamespace" comes from the ibd file itself, it can
6819 be different from data obtained from System tables since file
6820 operations are not transactional. If adjust_space is set, and the
6821 mismatching space are between a user table and its temp table, we
6822 shall adjust the ibd file name according to system table info */
6823
2/2
✓ Branch 0 taken 702 times.
✓ Branch 1 taken 70557 times.
71259 if (adjust_space && space != nullptr &&
6824
6/6
✓ Branch 0 taken 71259 times.
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 485 times.
✓ Branch 3 taken 217 times.
✓ Branch 4 taken 485 times.
✓ Branch 5 taken 70882 times.
143111 row_is_mysql_tmp_table_name(space->name) &&
6825
1/2
✓ Branch 0 taken 485 times.
✗ Branch 1 not taken.
485 !row_is_mysql_tmp_table_name(name)) {
6826 /* Atomic DDL's "ddl_log" will adjust the tablespace name. */
6827 485 mutex_release();
6828
6829 485 return true;
6830
6831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70882 times.
70882 } else if (!print_err) {
6832 ;
6833
6834 } else if (space == nullptr) {
6835 if (fnamespace == nullptr) {
6836 if (print_err) {
6837 fil_report_missing_tablespace(name, space_id);
6838 }
6839
6840 } else {
6841 ib::error(ER_IB_MSG_314)
6842 << "Table " << name << " in InnoDB data dictionary has tablespace id "
6843 << space_id << ", but a tablespace with that id does not exist."
6844 << " But there is a tablespace of name " << fnamespace->name
6845 << " and id " << fnamespace->id
6846 << ". Have you deleted or moved .ibd files?";
6847 }
6848
6849 ib::warn(ER_IB_MSG_315) << TROUBLESHOOT_DATADICT_MSG;
6850
6851 } else if (0 != strcmp(space->name, name)) {
6852 ib::error(ER_IB_MSG_316)
6853 << "Table " << name << " in InnoDB data dictionary"
6854 << " has tablespace id " << space_id
6855 << ", but the tablespace with that id has name " << space->name
6856 << ". Have you deleted or moved .ibd files?";
6857
6858 if (fnamespace != nullptr) {
6859 ib::error(ER_IB_MSG_317)
6860 << "There is a tablespace with the name " << fnamespace->name
6861 << ", but its id is " << fnamespace->id << ".";
6862 }
6863
6864 ib::warn(ER_IB_MSG_318) << TROUBLESHOOT_DATADICT_MSG;
6865 }
6866
6867 70882 mutex_release();
6868
6869 70882 return false;
6870 }
6871
6872 1287763 bool fil_space_exists_in_mem(space_id_t space_id, const char *name,
6873 bool print_err, bool adjust_space) {
6874 1287763 auto shard = fil_system->shard_by_id(space_id);
6875
6876 1287763 return shard->space_check_exists(space_id, name, print_err, adjust_space);
6877 }
6878 #endif /* !UNIV_HOTBACKUP */
6879
6880 /** Returns the space ID based on the tablespace name.
6881 The tablespace must be found in the tablespace memory cache.
6882 This call is made from external to this module, so the mutex is not owned.
6883 @param[in] name Tablespace name
6884 @return space ID if tablespace found, SPACE_UNKNOWN if space not. */
6885 169842 space_id_t fil_space_get_id_by_name(const char *name) {
6886 169842 auto space = fil_system->get_space_by_name(name);
6887
6888
2/2
✓ Branch 0 taken 168486 times.
✓ Branch 1 taken 1356 times.
169842 return (space == nullptr) ? SPACE_UNKNOWN : space->id;
6889 }
6890
6891 /** Fill the pages with NULs
6892 @param[in] file Tablespace file
6893 @param[in] page_size physical page size
6894 @param[in] start Offset from the start of the file in bytes
6895 @param[in] len Length in bytes
6896 @return DB_SUCCESS or error code */
6897 199909 static dberr_t fil_write_zeros(const fil_node_t *file, ulint page_size,
6898 os_offset_t start, os_offset_t len) {
6899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199909 times.
199909 ut_a(len > 0);
6900
6901 /* Extend at most 1M at a time */
6902 199909 os_offset_t n_bytes = std::min(static_cast<os_offset_t>(1024 * 1024), len);
6903
6904 199909 byte *buf = reinterpret_cast<byte *>(ut::aligned_zalloc(n_bytes, page_size));
6905
6906 199909 os_offset_t offset = start;
6907 199909 dberr_t err = DB_SUCCESS;
6908 199909 const os_offset_t end = start + len;
6909
1/2
✓ Branch 0 taken 199909 times.
✗ Branch 1 not taken.
199909 IORequest request(IORequest::WRITE);
6910
6911
2/2
✓ Branch 0 taken 209713 times.
✓ Branch 1 taken 199909 times.
409622 while (offset < end) {
6912 err =
6913
1/2
✓ Branch 0 taken 209713 times.
✗ Branch 1 not taken.
209713 os_file_write(request, file->name, file->handle, buf, offset, n_bytes);
6914
6915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209713 times.
209713 if (err != DB_SUCCESS) {
6916 break;
6917 }
6918
6919 209713 offset += n_bytes;
6920
6921 209713 n_bytes = std::min(n_bytes, end - offset);
6922
6923
2/6
✓ Branch 0 taken 209713 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 209713 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
209713 DBUG_EXECUTE_IF("ib_crash_during_tablespace_extension", DBUG_SUICIDE(););
6924 }
6925
6926 199909 ut::aligned_free(buf);
6927
6928 199909 return err;
6929 199909 }
6930
6931 /** Try to extend a tablespace if it is smaller than the specified size.
6932 @param[in,out] space tablespace
6933 @param[in] size desired size in pages
6934 @return whether the tablespace is at least as big as requested */
6935 299648 bool Fil_shard::space_extend(fil_space_t *space, page_no_t size) {
6936 /* In read-only mode we allow write to shared temporary tablespace
6937 as intrinsic table created by Optimizer reside in this tablespace. */
6938
5/8
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 299607 times.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 299648 times.
299648 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(space->id));
6939
6940 #ifndef UNIV_HOTBACKUP
6941
4/6
✓ Branch 0 taken 299648 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
✓ Branch 3 taken 299500 times.
✓ Branch 4 taken 148 times.
✗ Branch 5 not taken.
299648 DBUG_EXECUTE_IF("fil_space_print_xdes_pages",
6942 space->print_xdes_pages("xdes_pages.log"););
6943 #endif /* !UNIV_HOTBACKUP */
6944
6945 fil_node_t *file;
6946 299648 bool success = true;
6947
6948 #ifdef UNIV_HOTBACKUP
6949 page_no_t prev_size = 0;
6950 #endif /* UNIV_HOTBACKUP */
6951
6952 for (;;) {
6953
1/2
✓ Branch 0 taken 299648 times.
✗ Branch 1 not taken.
299648 mutex_acquire();
6954
1/2
✓ Branch 0 taken 299648 times.
✗ Branch 1 not taken.
299648 space = get_space_by_id(space->id);
6955
6956 /* Note:If the file is being opened for the first time then
6957 we don't have the file physical size. There is no guarantee
6958 that the file has been opened at this stage. */
6959
6960
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 299627 times.
299648 if (size < space->size) {
6961 /* Space already big enough */
6962
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 mutex_release();
6963
6964 21 return true;
6965 }
6966
6967 299627 file = &space->files.back();
6968
6969
1/2
✓ Branch 0 taken 299627 times.
✗ Branch 1 not taken.
299627 if (!file->is_being_extended) {
6970 /* Mark this file as undergoing extension. This flag
6971 is used to synchronize threads to execute space extension in order. */
6972
6973 299627 file->is_being_extended = true;
6974
6975 299627 break;
6976 }
6977
6978 /* Another thread is currently using the file. Wait
6979 for it to finish. It'd have been better to use an event
6980 driven mechanism but the entire module is peppered with
6981 polling code. */
6982
6983 mutex_release();
6984
6985 if (!tbsp_extend_and_initialize) {
6986 std::this_thread::sleep_for(std::chrono::microseconds(20));
6987 } else {
6988 std::this_thread::sleep_for(std::chrono::milliseconds(100));
6989 }
6990 }
6991
6992
2/4
✓ Branch 0 taken 299627 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 299627 times.
299627 if (!prepare_file_for_io(file)) {
6993 /* The tablespace data file, such as .ibd file, is missing */
6994 ut_a(file->is_being_extended);
6995 file->is_being_extended = false;
6996
6997 mutex_release();
6998
6999 return false;
7000 }
7001
7002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 299627 times.
299627 ut_a(file->is_open);
7003
7004
1/2
✓ Branch 0 taken 299627 times.
✗ Branch 1 not taken.
299627 const page_size_t page_size(space->flags);
7005
1/2
✓ Branch 0 taken 299627 times.
✗ Branch 1 not taken.
299627 const size_t phy_page_size = page_size.physical();
7006
7007 #ifdef UNIV_HOTBACKUP
7008 prev_size = space->size;
7009
7010 ib::trace_1() << "Extending space id : " << space->id
7011 << ", space name : " << space->name
7012 << ", space size : " << space->size
7013 << " pages, page size : " << phy_page_size
7014 << ", to size : " << size;
7015 #endif /* UNIV_HOTBACKUP */
7016
7017
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 299626 times.
299627 if (size <= space->size) {
7018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 ut_a(file->is_being_extended);
7019 1 file->is_being_extended = false;
7020
7021
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 complete_io(file, IORequestRead);
7022
7023
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mutex_release();
7024
7025 1 return true;
7026 }
7027
7028 /* At this point it is safe to release the shard mutex. No
7029 other thread can rename, delete or close the file because
7030 we have set the file->in_use flag. */
7031
7032
1/2
✓ Branch 0 taken 299626 times.
✗ Branch 1 not taken.
299626 mutex_release();
7033
7034 page_no_t pages_added;
7035
1/2
✓ Branch 0 taken 299626 times.
✗ Branch 1 not taken.
299626 os_offset_t node_start = os_file_get_size(file->handle);
7036
7037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 299626 times.
299626 ut_a(node_start != (os_offset_t)-1);
7038
7039 /* File first page number */
7040 299626 page_no_t node_first_page = space->size - file->size;
7041
7042 /* Number of physical pages in the file */
7043 299626 page_no_t n_node_physical_pages =
7044 299626 static_cast<page_no_t>(node_start / phy_page_size);
7045
7046 /* Number of pages to extend in the file */
7047 page_no_t n_node_extend;
7048
7049 299626 n_node_extend = size - (node_first_page + file->size);
7050
7051 /* If we already have enough physical pages to satisfy the
7052 extend request on the file then ignore it */
7053
1/2
✓ Branch 0 taken 299626 times.
✗ Branch 1 not taken.
299626 if (file->size + n_node_extend > n_node_physical_pages) {
7054
4/6
✓ Branch 0 taken 299626 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 299625 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
299626 DBUG_EXECUTE_IF("ib_crash_during_tablespace_extension", DBUG_SUICIDE(););
7055
7056 os_offset_t len;
7057 299625 dberr_t err = DB_SUCCESS;
7058
7059 299625 len = ((file->size + n_node_extend) * phy_page_size) - node_start;
7060
7061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 299625 times.
299625 ut_ad(len > 0);
7062
7063 #if !defined(UNIV_HOTBACKUP) && defined(UNIV_LINUX)
7064 /* Do not write redo log record for temporary tablespace
7065 and the system tablespace as they don't need to be recreated.
7066 Temporary tablespaces are reinitialized during startup and
7067 hence need not be recovered during recovery. The system
7068 tablespace is neither recreated nor resized and hence we do
7069 not need to redo log any operations on it. */
7070
5/6
✓ Branch 0 taken 299625 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 199784 times.
✓ Branch 3 taken 99841 times.
✓ Branch 4 taken 199762 times.
✓ Branch 5 taken 99863 times.
499409 if (!recv_recovery_is_on() && space->purpose != FIL_TYPE_TEMPORARY &&
7071
2/2
✓ Branch 0 taken 199762 times.
✓ Branch 1 taken 22 times.
199784 space->id != TRX_SYS_SPACE) {
7072 /* Write the redo log record for extending the space */
7073
1/2
✓ Branch 0 taken 199762 times.
✗ Branch 1 not taken.
199762 mtr_t mtr;
7074
1/2
✓ Branch 0 taken 199762 times.
✗ Branch 1 not taken.
199762 mtr_start(&mtr);
7075
7076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199762 times.
199762 ut_ad(node_start > 0);
7077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199762 times.
199762 ut_ad(len > 0);
7078
7079 /* The posix_fallocate() reserves the desired space and updates
7080 the file metadata in the filesystem. On successful execution, any
7081 subsequent attempt to access this newly allocated space will see
7082 it as initialized because of the updated filesystem metadata.
7083
7084 However, the posix_fallocate() call used to allocate space seems
7085 to have an atomicity issue where it can fail after reserving the
7086 space, but before updating the file metadata in the filesystem.
7087
7088 Offset is required to be written in the redo log record to find
7089 out the position in the file where it was extended during space
7090 extend operation. The offset value written in the redo log can
7091 be directly used to find the starting point for initializing
7092 the file during recovery. In case posix_fallocate() crashes as
7093 described above, it will be difficult to find out the old size
7094 of the file and hence it will be difficult to find out the exact
7095 region which needs to be initialized by writing 0's. */
7096
7097
1/2
✓ Branch 0 taken 199762 times.
✗ Branch 1 not taken.
199762 fil_op_write_space_extend(space->id, node_start, len, &mtr);
7098
7099
1/2
✓ Branch 0 taken 199762 times.
✗ Branch 1 not taken.
199762 mtr_commit(&mtr);
7100
7101
5/8
✓ Branch 0 taken 199762 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 199760 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
199762 DBUG_INJECT_CRASH_WITH_LOG_FLUSH("ib_crash_after_writing_redo_extend", 1);
7102
7103 /* NOTE: Though against for the Write-Ahead-Log principal,
7104 log_write_up_to() is not needed here, because no file shrinks and
7105 duplicate extending is allowed. And log_write_up_to() here helps
7106 nothing for fallocate() inconsistency. */
7107 199760 }
7108 #endif /* !UNIV_HOTBACKUP && UNIV_LINUX */
7109
7110 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
7111 /* This is required by FusionIO HW/Firmware */
7112
7113
1/2
✓ Branch 0 taken 299622 times.
✗ Branch 1 not taken.
299623 int ret = posix_fallocate(file->handle.m_file, node_start, len);
7114
7115
3/4
✓ Branch 0 taken 299622 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 299618 times.
299622 DBUG_EXECUTE_IF("ib_posix_fallocate_fail_eintr", ret = EINTR;);
7116
7117
2/4
✓ Branch 0 taken 299623 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 299623 times.
299622 DBUG_EXECUTE_IF("ib_posix_fallocate_fail_einval", ret = EINVAL;);
7118
7119
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 299619 times.
299623 if (ret != 0) {
7120 /* We already pass the valid offset and len in, if EINVAL
7121 is returned, it could only mean that the file system doesn't
7122 support fallocate(), currently one known case is ext3 with O_DIRECT.
7123
7124 Also because above call could be interrupted, in this case,
7125 simply go to plan B by writing zeroes.
7126
7127 Both error messages for above two scenarios are skipped in case
7128 of flooding error messages, because they can be ignored by users. */
7129
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 if (ret != EINTR && ret != EINVAL) {
7130 ib::error(ER_IB_MSG_319)
7131 << "posix_fallocate(): Failed to preallocate"
7132 " data for file "
7133 << file->name << ", desired size " << len
7134 << " bytes."
7135 " Operating system error number "
7136 << ret
7137 << ". Check"
7138 " that the disk is not full or a disk quota"
7139 " exceeded. Make sure the file system supports"
7140 " this function. Refer to your operating system"
7141 " documentation for operating system error code"
7142 " information.";
7143 }
7144
7145 4 err = DB_IO_ERROR;
7146 }
7147 #endif /* NO_FALLOCATE || !UNIV_LINUX */
7148
7149
6/6
✓ Branch 0 taken 299593 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 99804 times.
✓ Branch 3 taken 199789 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 99830 times.
299623 if ((tbsp_extend_and_initialize && !file->atomic_write) ||
7150 err == DB_IO_ERROR) {
7151
1/2
✓ Branch 0 taken 199793 times.
✗ Branch 1 not taken.
199793 err = fil_write_zeros(file, phy_page_size, node_start, len);
7152
7153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199793 times.
199793 if (err != DB_SUCCESS) {
7154 ib::warn(ER_IB_MSG_320)
7155 << "Error while writing " << len << " zeroes to " << file->name
7156 << " starting at offset " << node_start;
7157 }
7158 }
7159
7160 /* Check how many pages actually added */
7161
1/2
✓ Branch 0 taken 299623 times.
✗ Branch 1 not taken.
299623 os_offset_t end = os_file_get_size(file->handle);
7162
3/6
✓ Branch 0 taken 299623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299623 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 299622 times.
299623 ut_a(end != static_cast<os_offset_t>(-1) && end >= node_start);
7163
7164 299622 success = (end == node_start + len);
7165 299622 os_has_said_disk_full = !success;
7166
7167 299622 pages_added = static_cast<page_no_t>(end / phy_page_size);
7168
7169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 299623 times.
299622 ut_a(pages_added >= file->size);
7170 299623 pages_added -= file->size;
7171
7172 } else {
7173 success = true;
7174 pages_added = n_node_extend;
7175 os_has_said_disk_full = false;
7176 }
7177
7178
1/2
✓ Branch 0 taken 299622 times.
✗ Branch 1 not taken.
299623 mutex_acquire();
7179
7180 299622 file->size += pages_added;
7181 299622 space->size += pages_added;
7182
7183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 299623 times.
299622 ut_a(file->is_being_extended);
7184 299623 file->is_being_extended = false;
7185
7186
2/4
✓ Branch 0 taken 299622 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299622 times.
✗ Branch 3 not taken.
299623 complete_io(file, IORequestWrite);
7187
7188 #ifndef UNIV_HOTBACKUP
7189 /* Keep the last data file size info up to date, rounded to
7190 full megabytes */
7191 299622 page_no_t pages_per_mb =
7192 299622 static_cast<page_no_t>((1024 * 1024) / phy_page_size);
7193
7194 299622 page_no_t size_in_pages = ((file->size / pages_per_mb) * pages_per_mb);
7195
7196
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 299600 times.
299622 if (space->id == TRX_SYS_SPACE) {
7197
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 srv_sys_space.set_last_file_size(size_in_pages);
7198
3/4
✓ Branch 0 taken 299600 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99840 times.
✓ Branch 3 taken 199760 times.
299600 } else if (fsp_is_system_temporary(space->id)) {
7199
1/2
✓ Branch 0 taken 99839 times.
✗ Branch 1 not taken.
99840 srv_tmp_space.set_last_file_size(size_in_pages);
7200 }
7201 #else /* !UNIV_HOTBACKUP */
7202 ib::trace_2() << "Extended space : " << space->name << " from " << prev_size
7203 << " pages to " << space->size << " pages "
7204 << ", desired space size : " << size << " pages";
7205 #endif /* !UNIV_HOTBACKUP */
7206
7207
1/2
✓ Branch 0 taken 299621 times.
✗ Branch 1 not taken.
299621 space_flush(space->id);
7208
7209
1/2
✓ Branch 0 taken 299621 times.
✗ Branch 1 not taken.
299621 mutex_release();
7210
7211
2/6
✓ Branch 0 taken 299622 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 299622 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
299621 DBUG_EXECUTE_IF("fil_crash_after_extend", DBUG_SUICIDE(););
7212 299622 return success;
7213 }
7214
7215 /** Try to extend a tablespace if it is smaller than the specified size.
7216 @param[in,out] space Tablespace ID
7217 @param[in] size desired size in pages
7218 @return whether the tablespace is at least as big as requested */
7219 299648 bool fil_space_extend(fil_space_t *space, page_no_t size) {
7220 299648 auto shard = fil_system->shard_by_id(space->id);
7221
7222 299648 return shard->space_extend(space, size);
7223 }
7224
7225 #ifdef UNIV_HOTBACKUP
7226 /** Extends all tablespaces to the size stored in the space header. During the
7227 mysqlbackup --apply-log phase we extended the spaces on-demand so that log
7228 records could be applied, but that may have left spaces still too small
7229 compared to the size stored in the space header. */
7230 void Fil_shard::meb_extend_tablespaces_to_stored_len() {
7231 ut_ad(mutex_owned());
7232
7233 byte *buf = static_cast<byte *>(
7234 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, UNIV_PAGE_SIZE));
7235
7236 ut_a(buf != nullptr);
7237
7238 for (auto &elem : m_spaces) {
7239 auto space = elem.second;
7240
7241 ut_a(space->purpose == FIL_TYPE_TABLESPACE);
7242
7243 /* No need to protect with a mutex, because this is
7244 a single-threaded operation */
7245
7246 mutex_release();
7247
7248 dberr_t error;
7249
7250 const page_size_t page_size(space->flags);
7251
7252 error = fil_read(page_id_t(space->id, 0), page_size, 0,
7253 page_size.physical(), buf);
7254
7255 ut_a(error == DB_SUCCESS);
7256
7257 ulint size_in_header;
7258
7259 size_in_header = fsp_header_get_field(buf, FSP_SIZE);
7260
7261 bool success;
7262
7263 success = space_extend(space, size_in_header);
7264
7265 if (!success) {
7266 ib::error(ER_IB_MSG_321)
7267 << "Could not extend the tablespace of " << space->name
7268 << " to the size stored in"
7269 " header, "
7270 << size_in_header
7271 << " pages;"
7272 " size after extension "
7273 << 0
7274 << " pages. Check that you have free disk"
7275 " space and retry!";
7276
7277 ut_a(success);
7278 }
7279
7280 mutex_acquire();
7281 }
7282
7283 ut::free(buf);
7284 }
7285
7286 /** Extends all tablespaces to the size stored in the space header. During the
7287 mysqlbackup --apply-log phase we extended the spaces on-demand so that log
7288 records could be applied, but that may have left spaces still too small
7289 compared to the size stored in the space header. */
7290 void meb_extend_tablespaces_to_stored_len() {
7291 fil_system->meb_extend_tablespaces_to_stored_len();
7292 }
7293
7294 bool meb_is_redo_log_only_restore = false;
7295
7296 /** Determine if file is intermediate / temporary. These files are
7297 created during reorganize partition, rename tables, add / drop columns etc.
7298 @param[in] filepath absolute / relative or simply file name
7299 @retvalue true if it is intermediate file
7300 @retvalue false if it is normal file */
7301 bool meb_is_intermediate_file(const std::string &filepath) {
7302 std::string file_name = filepath;
7303
7304 {
7305 /** If its redo only restore, apply log needs to got through the
7306 intermediate steps to apply a ddl.
7307 Some of these operation might result in intermediate files.
7308 */
7309 if (meb_is_redo_log_only_restore) return false;
7310 /* extract file name from relative or absolute file name */
7311 auto pos = file_name.rfind(OS_PATH_SEPARATOR);
7312
7313 if (pos != std::string::npos) {
7314 ++pos;
7315 file_name = file_name.substr(pos);
7316 }
7317 }
7318
7319 transform(file_name.begin(), file_name.end(), file_name.begin(), ::tolower);
7320
7321 if (file_name[0] != '#') {
7322 auto pos = file_name.rfind("#tmp#.ibd");
7323 if (pos != std::string::npos) {
7324 return true;
7325 } else {
7326 return false; /* normal file name */
7327 }
7328 }
7329
7330 static std::vector<std::string> prefixes = {"#sql-", "#sql2-", "#tmp#",
7331 "#ren#"};
7332
7333 /* search for the unsupported patterns */
7334 for (const auto &prefix : prefixes) {
7335 if (Fil_path::has_prefix(file_name, prefix)) {
7336 return true;
7337 }
7338 }
7339
7340 return false;
7341 }
7342
7343 /** Return the space ID based of the remote general tablespace name.
7344 This is a wrapper over fil_space_get_id_by_name() method. it means,
7345 the tablespace must be found in the tablespace memory cache.
7346 This method extracts the tablespace name from input parameters and checks if
7347 it has been loaded in memory cache through either any of the remote general
7348 tablespaces directories identified at the time memory cache created.
7349 @param[in, out] tablespace Tablespace name
7350 @return space ID if tablespace found, SPACE_UNKNOWN if not found. */
7351 space_id_t meb_fil_space_get_rem_gen_ts_id_by_name(std::string &tablespace) {
7352 space_id_t space_id = SPACE_UNKNOWN;
7353
7354 for (auto newpath : rem_gen_ts_dirs) {
7355 auto pos = tablespace.rfind(OS_PATH_SEPARATOR);
7356
7357 if (pos == std::string::npos) {
7358 break;
7359 }
7360
7361 newpath += tablespace.substr(pos);
7362
7363 space_id = fil_space_get_id_by_name(newpath.c_str());
7364
7365 if (space_id != SPACE_UNKNOWN) {
7366 tablespace = newpath;
7367 break;
7368 }
7369 }
7370
7371 return space_id;
7372 }
7373
7374 /** Tablespace item during recovery */
7375 struct MEB_file_name {
7376 /** Constructor */
7377 MEB_file_name(std::string name, bool deleted)
7378 : m_name(name), m_space(), m_deleted(deleted) {}
7379
7380 /** Tablespace file name (MLOG_FILE_NAME) */
7381 std::string m_name;
7382
7383 /** Tablespace object (NULL if not valid or not found) */
7384 fil_space_t *m_space;
7385
7386 /** Whether the tablespace has been deleted */
7387 bool m_deleted;
7388 };
7389
7390 /** Map of dirty tablespaces during recovery */
7391 using MEB_recv_spaces =
7392 std::map<space_id_t, MEB_file_name, std::less<space_id_t>,
7393 ut::allocator<std::pair<const space_id_t, MEB_file_name>>>;
7394
7395 static MEB_recv_spaces recv_spaces;
7396
7397 /** Checks if MEB has loaded this space for reovery.
7398 @param[in] space_id Tablespace ID
7399 @return true if the space_id is loaded */
7400 bool meb_is_space_loaded(const space_id_t space_id) {
7401 return (recv_spaces.find(space_id) != recv_spaces.end());
7402 }
7403
7404 /** Set the keys for an encrypted tablespace.
7405 @param[in] space Tablespace for which to set the key */
7406 static void meb_set_encryption_key(const fil_space_t *space) {
7407 ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags));
7408
7409 for (auto &key : *recv_sys->keys) {
7410 if (key.space_id != space->id) {
7411 continue;
7412 }
7413
7414 dberr_t err;
7415
7416 err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv);
7417
7418 if (err != DB_SUCCESS) {
7419 ib::error(ER_IB_MSG_322) << "Can't set encryption information"
7420 << " for tablespace" << space->name << "!";
7421 }
7422
7423 ut::free(key.iv);
7424 ut::free(key.ptr);
7425
7426 key.iv = nullptr;
7427 key.ptr = nullptr;
7428 key.space_id = 0;
7429 }
7430 }
7431
7432 /** Process a file name passed as an input
7433 Wrapper around meb_name_process()
7434 @param[in,out] name absolute path of tablespace file
7435 @param[in] space_id The tablespace ID
7436 @param[in] deleted true if MLOG_FILE_DELETE */
7437 void Fil_system::meb_name_process(char *name, space_id_t space_id,
7438 bool deleted) {
7439 ut_ad(space_id != TRX_SYS_SPACE);
7440
7441 /* We will also insert space=nullptr into the map, so that
7442 further checks can ensure that a MLOG_FILE_NAME record was
7443 scanned before applying any page records for the space_id. */
7444
7445 Fil_path::normalize(name);
7446
7447 size_t len = std::strlen(name);
7448
7449 MEB_file_name fname(std::string(name, len - 1), deleted);
7450
7451 auto p = recv_spaces.insert(std::make_pair(space_id, fname));
7452
7453 ut_ad(p.first->first == space_id);
7454
7455 MEB_file_name &f = p.first->second;
7456
7457 if (deleted) {
7458 /* Got MLOG_FILE_DELETE */
7459
7460 if (!p.second && !f.m_deleted) {
7461 f.m_deleted = true;
7462
7463 if (f.m_space != nullptr) {
7464 f.m_space = nullptr;
7465 }
7466 }
7467
7468 ut_ad(f.m_space == nullptr);
7469
7470 } else if (p.second || f.m_name != fname.m_name) {
7471 fil_space_t *space;
7472
7473 /* Check if the tablespace file exists and contains
7474 the space_id. If not, ignore the file after displaying
7475 a note. Abort if there are multiple files with the
7476 same space_id. */
7477
7478 switch (ibd_open_for_recovery(space_id, name, space)) {
7479 case FIL_LOAD_OK:
7480 ut_ad(space != nullptr);
7481
7482 /* For encrypted tablespace, set key and iv. */
7483 if (FSP_FLAGS_GET_ENCRYPTION(space->flags) &&
7484 recv_sys->keys != nullptr) {
7485 meb_set_encryption_key(space);
7486 }
7487
7488 if (f.m_space == nullptr || f.m_space == space) {
7489 f.m_name = fname.m_name;
7490 f.m_space = space;
7491 f.m_deleted = false;
7492
7493 } else {
7494 ib::error(ER_IB_MSG_323)
7495 << "Tablespace " << space_id << " has been found in two places: '"
7496 << f.m_name << "' and '" << name
7497 << "'."
7498 " You must delete one of them.";
7499
7500 recv_sys->found_corrupt_fs = true;
7501 }
7502 break;
7503
7504 case FIL_LOAD_ID_CHANGED:
7505 ut_ad(space == nullptr);
7506
7507 ib::trace_1() << "Ignoring file " << name << " for space-id mismatch "
7508 << space_id;
7509 break;
7510
7511 case FIL_LOAD_NOT_FOUND:
7512 /* No matching tablespace was found; maybe it
7513 was renamed, and we will find a subsequent
7514 MLOG_FILE_* record. */
7515 ut_ad(space == nullptr);
7516 break;
7517
7518 case FIL_LOAD_INVALID:
7519 ut_ad(space == nullptr);
7520
7521 ib::warn(ER_IB_MSG_324) << "Invalid tablespace " << name;
7522 break;
7523
7524 case FIL_LOAD_MISMATCH:
7525 ut_ad(space == nullptr);
7526 break;
7527 case FIL_LOAD_DBWLR_CORRUPTION:
7528 ut_ad(space == nullptr);
7529 break;
7530 }
7531 }
7532 }
7533
7534 /** Process a file name passed as an input
7535 Wrapper around meb_name_process()
7536 @param[in] name absolute path of tablespace file
7537 @param[in] space_id the tablespace ID */
7538 void meb_fil_name_process(const char *name, space_id_t space_id) {
7539 char *file_name = static_cast<char *>(mem_strdup(name));
7540
7541 fil_system->meb_name_process(file_name, space_id, false);
7542
7543 ut::free(file_name);
7544 }
7545
7546 /** Test, if a file path name contains a back-link ("../").
7547 We assume a path to a file. So we don't check for a trailing "/..".
7548 @param[in] path path to check
7549 @return whether the path contains a back-link.
7550 */
7551 static bool meb_has_back_link(const std::string &path) {
7552 #ifdef _WIN32
7553 static const std::string DOT_DOT_SLASH = "..\\";
7554 static const std::string SLASH_DOT_DOT_SLASH = "\\..\\";
7555 #else
7556 static const std::string DOT_DOT_SLASH = "../";
7557 static const std::string SLASH_DOT_DOT_SLASH = "/../";
7558 #endif /* _WIN32 */
7559 return ((0 == path.compare(0, 3, DOT_DOT_SLASH)) ||
7560 (std::string::npos != path.find(SLASH_DOT_DOT_SLASH)));
7561 }
7562
7563 /** Parse a file name retrieved from a MLOG_FILE_* record,
7564 and return the absolute file path corresponds to backup dir
7565 as well as in the form of database/tablespace
7566 @param[in] name path emitted by the redo log
7567 @param[in] flags flags emitted by the redo log
7568 @param[in] space_id space_id emmited by the redo log
7569 @param[out] absolute_path absolute path of tablespace
7570 corresponds to target dir
7571 @param[out] tablespace_name name in the form of database/table */
7572 static void meb_make_abs_file_path(const std::string &name, uint32_t flags,
7573 space_id_t space_id,
7574 std::string &absolute_path,
7575 std::string &tablespace_name) {
7576 Datafile df;
7577 std::string file_name = name;
7578
7579 /* If the tablespace path name is absolute or has back-links ("../"),
7580 we assume, that it is located outside of datadir. */
7581 if (Fil_path::is_absolute_path(file_name.c_str()) ||
7582 (meb_has_back_link(file_name) && !replay_in_datadir)) {
7583 if (replay_in_datadir) {
7584 /* This is an apply-log in the restored datadir. Take the path as is. */
7585 df.set_filepath(file_name.c_str());
7586 } else {
7587 /* This is an apply-log in backup_dir/datadir. Get the file inside. */
7588 auto pos = file_name.rfind(OS_PATH_SEPARATOR);
7589
7590 /* if it is file per tablespace, then include the schema
7591 directory as well */
7592 if (fsp_is_file_per_table(space_id, flags) && pos != std::string::npos) {
7593 pos = file_name.rfind(OS_PATH_SEPARATOR, pos - 1);
7594 }
7595
7596 if (pos == std::string::npos) {
7597 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_325)
7598 << "Could not extract the tablespace"
7599 << " file name from the in the path : " << name;
7600 }
7601
7602 ++pos;
7603
7604 file_name = file_name.substr(pos);
7605
7606 df.make_filepath(MySQL_datadir_path, file_name.c_str(), IBD);
7607 }
7608
7609 } else {
7610 /* This is an apply-log with a relative path, either in the restored
7611 datadir, or in backup_dir/datadir. If in the restored datadir, the
7612 path might start with "../" to reach outside of datadir. */
7613 auto pos = file_name.find(OS_PATH_SEPARATOR);
7614
7615 /* Remove the cur dir from the path as this will cause the
7616 path name mismatch when we try to find out the space_id based
7617 on tablespace name */
7618
7619 if (file_name.substr(0, pos) == ".") {
7620 ++pos;
7621 file_name = file_name.substr(pos);
7622 }
7623
7624 /* make_filepath() does not prepend the directory, if the file name
7625 starts with "../". Prepend it unconditionally here. */
7626 file_name.insert(0, 1, OS_PATH_SEPARATOR);
7627 file_name.insert(0, MySQL_datadir_path);
7628
7629 df.make_filepath(nullptr, file_name.c_str(), IBD);
7630 }
7631
7632 df.set_flags(flags);
7633 df.set_space_id(space_id);
7634 df.set_name(nullptr);
7635
7636 absolute_path = df.filepath();
7637
7638 tablespace_name = df.name();
7639 }
7640
7641 /** Process a MLOG_FILE_CREATE redo record.
7642 @param[in] page_id Page id of the redo log record
7643 @param[in] flags Tablespace flags
7644 @param[in] name Tablespace filename */
7645 static void meb_tablespace_redo_create(const page_id_t &page_id, uint32_t flags,
7646 const char *name) {
7647 std::string abs_file_path;
7648 std::string tablespace_name;
7649
7650 meb_make_abs_file_path(name, flags, page_id.space(), abs_file_path,
7651 tablespace_name);
7652
7653 if (meb_is_intermediate_file(abs_file_path.c_str()) ||
7654 fil_space_get(page_id.space()) ||
7655 fil_space_get_id_by_name(tablespace_name.c_str()) != SPACE_UNKNOWN ||
7656 meb_fil_space_get_rem_gen_ts_id_by_name(tablespace_name) !=
7657 SPACE_UNKNOWN) {
7658 /* Don't create table while :-
7659 1. scanning the redo logs during backup
7660 2. apply-log on a partial backup
7661 3. if it is intermediate file
7662 4. tablespace is already loaded in memory
7663 5. tablespace is a remote general tablespace which is
7664 already loaded for recovery/apply-log from different
7665 directory path */
7666
7667 ib::trace_1() << "Ignoring the log record. No need to "
7668 << "create the tablespace : " << abs_file_path;
7669 } else {
7670 auto it = recv_spaces.find(page_id.space());
7671
7672 if (it == recv_spaces.end() || it->second.m_name != abs_file_path) {
7673 ib::trace_1() << "Creating the tablespace : " << abs_file_path
7674 << ", space_id : " << page_id.space();
7675
7676 dberr_t ret = fil_ibd_create(page_id.space(), tablespace_name.c_str(),
7677 abs_file_path.c_str(), flags,
7678 FIL_IBD_FILE_INITIAL_SIZE);
7679
7680 if (ret != DB_SUCCESS) {
7681 ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_326)
7682 << "Could not create the tablespace : " << abs_file_path
7683 << " with space Id : " << page_id.space();
7684 }
7685 }
7686 }
7687 }
7688
7689 /** Process a MLOG_FILE_RENAME redo record.
7690 @param[in] page_id Page id of the redo log record
7691 @param[in] from_name Tablespace from filename
7692 @param[in] to_name Tablespace to filename */
7693 static void meb_tablespace_redo_rename(const page_id_t &page_id,
7694 const char *from_name,
7695 const char *to_name) {
7696 std::string abs_to_path;
7697 std::string abs_from_path;
7698 std::string tablespace_name;
7699
7700 meb_make_abs_file_path(from_name, 0, page_id.space(), abs_from_path,
7701 tablespace_name);
7702
7703 meb_make_abs_file_path(to_name, 0, page_id.space(), abs_to_path,
7704 tablespace_name);
7705
7706 char *new_name = nullptr;
7707
7708 if (meb_is_intermediate_file(from_name) ||
7709 meb_is_intermediate_file(to_name) ||
7710 fil_space_get_id_by_name(tablespace_name.c_str()) != SPACE_UNKNOWN ||
7711 meb_fil_space_get_rem_gen_ts_id_by_name(tablespace_name) !=
7712 SPACE_UNKNOWN ||
7713 fil_space_get(page_id.space()) == nullptr) {
7714 /* Don't rename table while :
7715 1. Scanning the redo logs during backup
7716 2. Apply-log on a partial backup
7717 3. Either of old or new tables are intermediate table
7718 4. The new name is already loaded for recovery/apply-log
7719 5. The new name is a remote general tablespace which is
7720 already loaded for recovery/apply-log from different
7721 directory path
7722 6. Tablespace is not yet loaded in memory.
7723 This will prevent unintended renames during recovery. */
7724
7725 ib::trace_1() << "Ignoring the log record. "
7726 << "No need to rename tablespace";
7727
7728 return;
7729
7730 } else {
7731 ib::trace_1() << "Renaming space id : " << page_id.space()
7732 << ", old tablespace name : " << from_name
7733 << " to new tablespace name : " << to_name;
7734
7735 new_name = static_cast<char *>(mem_strdup(abs_to_path.c_str()));
7736 }
7737
7738 meb_fil_name_process(from_name, page_id.space());
7739 meb_fil_name_process(new_name, page_id.space());
7740
7741 if (!fil_op_replay_rename(page_id, abs_from_path.c_str(),
7742 abs_to_path.c_str())) {
7743 recv_sys->found_corrupt_fs = true;
7744 }
7745
7746 meb_fil_name_process(to_name, page_id.space());
7747
7748 ut::free(new_name);
7749 }
7750
7751 /** Process a MLOG_FILE_DELETE redo record.
7752 @param[in] page_id Page id of the redo log record
7753 @param[in] name Tablespace filename */
7754 static void meb_tablespace_redo_delete(const page_id_t &page_id,
7755 const char *name) {
7756 std::string abs_file_path;
7757 std::string tablespace_name;
7758
7759 meb_make_abs_file_path(name, 0, page_id.space(), abs_file_path,
7760 tablespace_name);
7761
7762 char *file_name = static_cast<char *>(mem_strdup(name));
7763
7764 fil_system->meb_name_process(file_name, page_id.space(), true);
7765
7766 if (fil_space_get(page_id.space())) {
7767 ib::trace_1() << "Deleting the tablespace : " << abs_file_path
7768 << ", space_id : " << page_id.space();
7769 dberr_t err =
7770 fil_delete_tablespace(page_id.space(), BUF_REMOVE_FLUSH_NO_WRITE);
7771
7772 ut_a(err == DB_SUCCESS);
7773 }
7774
7775 ut::free(file_name);
7776 }
7777
7778 #endif /* UNIV_HOTBACKUP */
7779
7780 /*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/
7781
7782 /** Tries to reserve free extents in a file space.
7783 @param[in] space_id Tablespace ID
7784 @param[in] n_free_now Number of free extents now
7785 @param[in] n_to_reserve How many one wants to reserve
7786 @return true if succeed */
7787 9925056 bool fil_space_reserve_free_extents(space_id_t space_id, ulint n_free_now,
7788 ulint n_to_reserve) {
7789 9925056 auto shard = fil_system->shard_by_id(space_id);
7790
7791 9925059 shard->mutex_acquire();
7792
7793 9925058 fil_space_t *space = shard->get_space_by_id(space_id);
7794
7795 bool success;
7796
7797
2/2
✓ Branch 0 taken 4727 times.
✓ Branch 1 taken 9920331 times.
9925058 if (space->n_reserved_extents + n_to_reserve > n_free_now) {
7798 4727 success = false;
7799 } else {
7800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9920331 times.
9920331 ut_a(n_to_reserve < std::numeric_limits<uint32_t>::max());
7801 9920331 space->n_reserved_extents += (uint32_t)n_to_reserve;
7802 9920331 success = true;
7803 }
7804
7805 9925058 shard->mutex_release();
7806
7807 9925057 return success;
7808 }
7809
7810 /** Releases free extents in a file space.
7811 @param[in] space_id Tablespace ID
7812 @param[in] n_reserved How many were reserved */
7813 11744352 void fil_space_release_free_extents(space_id_t space_id, ulint n_reserved) {
7814 11744352 auto shard = fil_system->shard_by_id(space_id);
7815
7816 11744356 shard->mutex_acquire();
7817
7818 11744354 fil_space_t *space = shard->get_space_by_id(space_id);
7819
7820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11744353 times.
11744351 ut_a(n_reserved < std::numeric_limits<uint32_t>::max());
7821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11744352 times.
11744353 ut_a(space->n_reserved_extents >= n_reserved);
7822
7823 11744352 space->n_reserved_extents -= (uint32_t)n_reserved;
7824
7825 11744352 shard->mutex_release();
7826 11744356 }
7827
7828 /** Gets the number of reserved extents. If the database is silent, this number
7829 should be zero.
7830 @param[in] space_id Tablespace ID
7831 @return the number of reserved extents */
7832 1853767 ulint fil_space_get_n_reserved_extents(space_id_t space_id) {
7833 1853767 auto shard = fil_system->shard_by_id(space_id);
7834
7835 1853767 shard->mutex_acquire();
7836
7837 1853767 fil_space_t *space = shard->get_space_by_id(space_id);
7838
7839 1853767 ulint n = space->n_reserved_extents;
7840
7841 1853767 shard->mutex_release();
7842
7843 1853767 return n;
7844 }
7845
7846 /*============================ FILE I/O ================================*/
7847
7848 78424854 bool Fil_shard::prepare_file_for_io(fil_node_t *file) {
7849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78425222 times.
78424854 ut_ad(mutex_owned());
7850
7851 78425222 fil_space_t *space = file->space;
7852
7853
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78425205 times.
78425222 if (space->is_deleted()) {
7854 return false;
7855 }
7856
7857
2/2
✓ Branch 0 taken 335054 times.
✓ Branch 1 taken 78090151 times.
78425205 if (!file->is_open) {
7858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 335054 times.
335054 ut_a(file->n_pending_ios == 0);
7859
7860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 335051 times.
335054 if (!open_file(file)) {
7861 return false;
7862 }
7863 }
7864
2/2
✓ Branch 0 taken 72103459 times.
✓ Branch 1 taken 6321743 times.
78425202 if (file->n_pending_ios == 0) {
7865 72103459 remove_from_LRU(file);
7866 }
7867
7868 78425177 ++file->n_pending_ios;
7869
7870 /* The file can't be in the LRU list. */
7871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78425349 times.
78425177 ut_ad(!ut_list_exists(m_LRU, file));
7872
7873 78425349 return true;
7874 }
7875
7876 /** If the tablespace is not on the unflushed list, add it.
7877 @param[in,out] space Tablespace to add */
7878 19199367 void Fil_shard::add_to_unflushed_list(fil_space_t *space) {
7879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19199412 times.
19199367 ut_ad(mutex_owned());
7880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19199405 times.
19199412 ut_a(space->purpose != FIL_TYPE_TEMPORARY);
7881
7882
2/2
✓ Branch 0 taken 9989090 times.
✓ Branch 1 taken 9210315 times.
19199405 if (!space->is_in_unflushed_spaces) {
7883 9989090 space->is_in_unflushed_spaces = true;
7884
7885 9989090 UT_LIST_ADD_FIRST(m_unflushed_spaces, space);
7886 }
7887 19199463 }
7888
7889 /** Note that a write IO has completed.
7890 @param[in,out] file File on which a write was completed */
7891 21503103 void Fil_shard::write_completed(fil_node_t *file) {
7892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21503128 times.
21503103 ut_ad(mutex_owned());
7893
7894 21503128 ++m_modification_counter;
7895
7896 21503128 file->modification_counter = m_modification_counter;
7897
7898
2/2
✓ Branch 0 taken 2303708 times.
✓ Branch 1 taken 19199396 times.
21503128 if (fil_disable_space_flushing(file->space)) {
7899 /* We don't need to keep track of not flushed changes as either:
7900 - user has explicitly disabled buffering,
7901 - or it is FIL_TYPE_TEMPORARY space and we don't ever flush these. */
7902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2303708 times.
2303708 ut_ad(!file->space->is_in_unflushed_spaces);
7903
7904 2303708 file->set_flushed();
7905
7906 } else {
7907 19199396 add_to_unflushed_list(file->space);
7908 }
7909 21503235 }
7910
7911 /** Updates the data structures when an I/O operation finishes. Updates the
7912 pending I/O's field in the file appropriately.
7913 @param[in] file Tablespace file
7914 @param[in] type Marks the file as modified type == WRITE */
7915 78425060 void Fil_shard::complete_io(fil_node_t *file, const IORequest &type) {
7916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78425078 times.
78425060 ut_ad(mutex_owned());
7917
7918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78424992 times.
78425078 ut_a(file->n_pending_ios > 0);
7919
7920 78424992 --file->n_pending_ios;
7921
7922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78424971 times.
78424992 ut_ad(type.validate());
7923
7924
2/2
✓ Branch 0 taken 21503113 times.
✓ Branch 1 taken 56921896 times.
78424971 if (type.is_write()) {
7925
4/6
✓ Branch 0 taken 5955 times.
✓ Branch 1 taken 21497158 times.
✓ Branch 2 taken 5955 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21503125 times.
21503113 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(file->space->id));
7926
7927 21503125 write_completed(file);
7928 }
7929
7930
2/2
✓ Branch 0 taken 72103508 times.
✓ Branch 1 taken 6321623 times.
78425131 if (file->n_pending_ios == 0) {
7931 /* The file must be put back to the LRU list */
7932 72103508 add_to_lru_if_needed(file);
7933 }
7934 78425180 }
7935
7936 /** Report information about an invalid page access.
7937 @param[in] block_offset Block offset
7938 @param[in] space_id Tablespace ID
7939 @param[in] space_name Tablespace name
7940 @param[in] byte_offset Byte offset
7941 @param[in] len I/O length
7942 @param[in] is_read I/O type
7943 @param[in] line Line called from */
7944 static void fil_report_invalid_page_access_low(page_no_t block_offset,
7945 space_id_t space_id,
7946 const char *space_name,
7947 ulint byte_offset, ulint len,
7948 bool is_read, int line) {
7949 ib::error(ER_IB_MSG_328)
7950 << "Trying to access page number " << block_offset
7951 << " in"
7952 " space "
7953 << space_id << ", space name " << space_name
7954 << ","
7955 " which is outside the tablespace bounds. Byte offset "
7956 << byte_offset << ", len " << len << ", i/o type "
7957 << (is_read ? "read" : "write")
7958 << ". If you get this error at mysqld startup, please check"
7959 " that your my.cnf matches the ibdata files that you have in"
7960 " the MySQL server.";
7961
7962 ib::error(ER_IB_MSG_329) << "Server exits"
7963 #ifdef UNIV_DEBUG
7964 << " at "
7965 << "fil0fil.cc"
7966 << "[" << line << "]"
7967 #endif /* UNIV_DEBUG */
7968 << ".";
7969
7970 ut_error;
7971 }
7972
7973 #define fil_report_invalid_page_access(b, s, n, o, l, t) \
7974 fil_report_invalid_page_access_low((b), (s), (n), (o), (l), (t), __LINE__)
7975
7976 /** Set encryption information for IORequest.
7977 @param[in,out] req_type IO request
7978 @param[in] page_id page id
7979 @param[in] space table space */
7980 78074218 void fil_io_set_encryption(IORequest &req_type, const page_id_t &page_id,
7981 fil_space_t *space) {
7982 // TODO: now that dblwr doesn't exist in sys , should we encrypt all pages?
7983 // Or is there performance impact by encrypting TRX_SYS_PAGE which is
7984 // modified on every trx commit (binlog position is written)
7985
7986 /* Don't encrypt pages of system tablespace upto TRX_SYS_PAGE(including). The
7987 doublewrite buffer header is on TRX_SYS_PAGE */
7988
8/8
✓ Branch 0 taken 1494403 times.
✓ Branch 1 taken 76579846 times.
✓ Branch 2 taken 1494067 times.
✓ Branch 3 taken 336 times.
✓ Branch 4 taken 1240265 times.
✓ Branch 5 taken 253802 times.
✓ Branch 6 taken 1240265 times.
✓ Branch 7 taken 76833984 times.
79568285 if (fsp_is_system_tablespace(space->id) && space->crypt_data == nullptr &&
7989 1494067 page_id.page_no() <= FSP_TRX_SYS_PAGE_NO) {
7990 1240265 req_type.clear_encrypted();
7991 1240265 return;
7992 }
7993
7994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76834062 times.
76833984 ut_a(!req_type.is_log());
7995 /* Don't encrypt page 0 of all tablespaces except redo log
7996 tablespace, all pages from the system tablespace. */
7997
2/2
✓ Branch 0 taken 74843 times.
✓ Branch 1 taken 42683 times.
117526 if ((space->encryption_op_in_progress == Encryption::Progress::DECRYPTION &&
7998 117526 req_type.is_write()) ||
7999
8/8
✓ Branch 0 taken 117526 times.
✓ Branch 1 taken 76716536 times.
✓ Branch 2 taken 1420311 times.
✓ Branch 3 taken 75371069 times.
✓ Branch 4 taken 17254 times.
✓ Branch 5 taken 1403060 times.
✓ Branch 6 taken 75431046 times.
✓ Branch 7 taken 1403020 times.
76951588 !space->can_encrypt() || page_id.page_no() == 0) {
8000 75431046 req_type.clear_encrypted();
8001 75431075 return;
8002 }
8003
8004 /* For writing temporary tablespace, if encryption for temporary
8005 tablespace is disabled, skip setting encryption.
8006 Encryption of session temporary tablespaces is independent of
8007 innodb_temp_tablespace_encrypt */
8008
8/8
✓ Branch 0 taken 6140 times.
✓ Branch 1 taken 1396921 times.
✓ Branch 2 taken 285 times.
✓ Branch 3 taken 5855 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 247 times.
✓ Branch 6 taken 38 times.
✓ Branch 7 taken 1403023 times.
1403305 if (fsp_is_global_temporary(space->id) && !srv_tmp_tablespace_encrypt &&
8009 285 req_type.is_write()) {
8010 38 req_type.clear_encrypted();
8011 38 return;
8012 }
8013
8014 /* For writing undo log, if encryption for undo log is disabled,
8015 skip set encryption. */
8016
8/8
✓ Branch 0 taken 789896 times.
✓ Branch 1 taken 613125 times.
✓ Branch 2 taken 75691 times.
✓ Branch 3 taken 714205 times.
✓ Branch 4 taken 6154 times.
✓ Branch 5 taken 69537 times.
✓ Branch 6 taken 6154 times.
✓ Branch 7 taken 1396867 times.
1478714 if (fsp_is_undo_tablespace(space->id) && !srv_undo_log_encrypt &&
8017 75691 req_type.is_write()) {
8018 6154 req_type.clear_encrypted();
8019 6154 return;
8020 }
8021
8022
2/2
✓ Branch 0 taken 554633 times.
✓ Branch 1 taken 842233 times.
1396867 if (req_type.get_encrypted_block() != nullptr) {
8023 /* Already encrypted. */
8024 554633 req_type.clear_encrypted();
8025 554635 return;
8026 }
8027
8028 842233 req_type.encryption_key(space->m_encryption_metadata.m_key,
8029 space->m_encryption_metadata.m_key_len,
8030 842233 space->m_encryption_metadata.m_iv);
8031
8032 842234 req_type.encryption_algorithm(Encryption::AES);
8033 }
8034
8035 78074008 AIO_mode Fil_shard::get_AIO_mode(const IORequest &, bool sync) {
8036 #ifndef UNIV_HOTBACKUP
8037
2/2
✓ Branch 0 taken 55976343 times.
✓ Branch 1 taken 22097665 times.
78074008 if (sync) {
8038 55976343 return AIO_mode::SYNC;
8039
8040 } else {
8041 22097665 return AIO_mode::NORMAL;
8042 }
8043 #else /* !UNIV_HOTBACKUP */
8044 ut_a(sync);
8045 return AIO_mode::SYNC;
8046 #endif /* !UNIV_HOTBACKUP */
8047 }
8048
8049 78074310 dberr_t Fil_shard::get_file_for_io(fil_space_t *space, page_no_t *page_no,
8050 fil_node_t *&file) {
8051 78074310 file = space->get_file_node(page_no);
8052
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 78074383 times.
78074624 return (file == nullptr) ? DB_ERROR : DB_SUCCESS;
8053 }
8054
8055 78074653 dberr_t Fil_shard::do_io(const IORequest &type, bool sync,
8056 const page_id_t &page_id, const page_size_t &page_size,
8057 ulint byte_offset, ulint len, void *buf, void *message,
8058 trx_t *trx, bool should_buffer) {
8059 78074653 IORequest req_type(type);
8060
8061
2/4
✓ Branch 0 taken 78075386 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78075378 times.
78075252 ut_ad(req_type.validate());
8062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78074905 times.
78075378 ut_ad(!req_type.is_log());
8063
8064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78075295 times.
78074905 ut_ad(len > 0);
8065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78075283 times.
78075295 ut_ad(byte_offset < UNIV_PAGE_SIZE);
8066
4/6
✓ Branch 0 taken 117765 times.
✓ Branch 1 taken 77957418 times.
✓ Branch 2 taken 117765 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78075142 times.
78075283 ut_ad(!page_size.is_compressed() || byte_offset == 0);
8067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78075071 times.
78075142 ut_ad(UNIV_PAGE_SIZE == (ulong)(1 << UNIV_PAGE_SIZE_SHIFT));
8068
8069
2/4
✓ Branch 0 taken 78074919 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78074985 times.
78075071 ut_ad(fil_validate_skip());
8070
8071 #ifndef UNIV_HOTBACKUP
8072 /* ibuf bitmap pages must be read in the sync AIO mode: */
8073
9/12
✓ Branch 0 taken 77978070 times.
✓ Branch 1 taken 96915 times.
✓ Branch 2 taken 56813362 times.
✓ Branch 3 taken 21164697 times.
✓ Branch 4 taken 56813389 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117826 times.
✓ Branch 7 taken 56695563 times.
✓ Branch 8 taken 117826 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 78075021 times.
78074985 ut_ad(recv_no_ibuf_operations || req_type.is_write() ||
8074 !ibuf_bitmap_page(page_id, page_size) || sync);
8075
8076
1/2
✓ Branch 0 taken 78074915 times.
✗ Branch 1 not taken.
78075021 auto aio_mode = get_AIO_mode(req_type, sync);
8077
8078
2/2
✓ Branch 0 taken 56871153 times.
✓ Branch 1 taken 21203901 times.
78074915 if (req_type.is_read()) {
8079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56871125 times.
56871153 ut_ad(type.get_original_size() == 0);
8080
1/2
✓ Branch 0 taken 56871081 times.
✗ Branch 1 not taken.
56871125 srv_stats.data_read.add(len);
8081
8082
5/6
✓ Branch 0 taken 1061026 times.
✓ Branch 1 taken 55810055 times.
✓ Branch 2 taken 1003873 times.
✓ Branch 3 taken 57153 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 56871081 times.
57874954 if (aio_mode == AIO_mode::NORMAL && !recv_no_ibuf_operations &&
8083
2/4
✓ Branch 0 taken 1003873 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1003873 times.
1003873 ibuf_page(page_id, page_size, UT_LOCATION_HERE, nullptr)) {
8084 /* Reduce probability of deadlock bugs
8085 in connection with ibuf: do not let the
8086 ibuf I/O handler sleep */
8087
8088 req_type.clear_do_not_wake();
8089
8090 aio_mode = AIO_mode::IBUF;
8091 }
8092
8093 #ifdef UNIV_DEBUG
8094
1/2
✓ Branch 0 taken 56871245 times.
✗ Branch 1 not taken.
56871081 mutex_acquire();
8095 /* Should never attempt to read from a deleted tablespace, unless we
8096 are also importing the tablespace. By the time we get here in the final
8097 phase of import the state has changed. Therefore we check if there is
8098 an active fil_space_t instance with the same ID. */
8099
2/2
✓ Branch 0 taken 225114 times.
✓ Branch 1 taken 56871229 times.
57096359 for (auto pair : m_deleted_spaces) {
8100
2/2
✓ Branch 0 taken 3628 times.
✓ Branch 1 taken 221486 times.
225114 if (pair.first == page_id.space()) {
8101
1/2
✓ Branch 0 taken 3628 times.
✗ Branch 1 not taken.
3628 auto space = get_space_by_id(page_id.space());
8102
1/2
✓ Branch 0 taken 3628 times.
✗ Branch 1 not taken.
3628 if (space != nullptr) {
8103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3628 times.
3628 ut_a(pair.second != space);
8104 }
8105 }
8106 }
8107
1/2
✓ Branch 0 taken 56871249 times.
✗ Branch 1 not taken.
56871229 mutex_release();
8108 #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
8109
8110
1/2
✓ Branch 0 taken 21204185 times.
✗ Branch 1 not taken.
21203901 } else if (req_type.is_write()) {
8111
5/8
✓ Branch 0 taken 5914 times.
✓ Branch 1 taken 21198271 times.
✓ Branch 2 taken 5867 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5865 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 21204194 times.
21204185 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space()));
8112
8113
1/2
✓ Branch 0 taken 21204202 times.
✗ Branch 1 not taken.
21204194 srv_stats.data_written.add(len);
8114 }
8115 #else /* !UNIV_HOTBACKUP */
8116 ut_a(sync);
8117 auto aio_mode = AIO_mode::SYNC;
8118 #endif /* !UNIV_HOTBACKUP */
8119
8120 /* Reserve the mutex and make sure that we can open at
8121 least one file while holding it, if the file is not already open */
8122
8123 78075417 auto bpage = static_cast<buf_page_t *>(message);
8124
8125
1/2
✓ Branch 0 taken 78075490 times.
✗ Branch 1 not taken.
78075417 mutex_acquire();
8126
1/2
✓ Branch 0 taken 78075343 times.
✗ Branch 1 not taken.
78075490 auto space = get_space_by_id(page_id.space());
8127
8128 /* If we are deleting a tablespace we don't allow async read
8129 operations on that. However, we do allow write operations and
8130 sync read operations. */
8131
6/6
✓ Branch 0 taken 78074443 times.
✓ Branch 1 taken 900 times.
✓ Branch 2 taken 56871257 times.
✓ Branch 3 taken 21203179 times.
✓ Branch 4 taken 933 times.
✓ Branch 5 taken 78074403 times.
213021036 if (space == nullptr ||
8132
4/4
✓ Branch 0 taken 1061027 times.
✓ Branch 1 taken 55810230 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 1060994 times.
134945700 (req_type.is_read() && !sync && space->stop_new_ops)) {
8133 #ifndef UNIV_HOTBACKUP
8134
3/6
✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 933 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 933 times.
✗ Branch 5 not taken.
933 const auto is_page_stale = bpage != nullptr && bpage->is_stale();
8135 #endif /* !UNIV_HOTBACKUP */
8136
8137
1/2
✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
933 mutex_release();
8138
8139
1/2
✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
933 if (space == nullptr) {
8140 #ifndef UNIV_HOTBACKUP
8141
3/6
✓ Branch 0 taken 933 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 933 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 933 times.
✗ Branch 5 not taken.
933 if (req_type.is_write() && is_page_stale) {
8142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 933 times.
933 ut_a(bpage->get_space()->id == page_id.space());
8143 933 return DB_PAGE_IS_STALE;
8144 }
8145 #endif /* !UNIV_HOTBACKUP */
8146
8147 if (!req_type.ignore_missing()) {
8148 #ifndef UNIV_HOTBACKUP
8149 /* Don't have any record of this tablespace. print a warning. */
8150 if (!Fil_shard::is_deleted(page_id.space())) {
8151 #endif /* !UNIV_HOTBACKUP */
8152 if (space == nullptr) {
8153 ib::error(ER_IB_MSG_330)
8154 << "Trying to do I/O on a tablespace"
8155 << " which does not exist. I/O type: "
8156 << (req_type.is_read() ? "read" : "write")
8157 << ", page: " << page_id << ", I/O length: " << len << " bytes";
8158 } else {
8159 ib::error(ER_IB_MSG_331)
8160 << "Trying to do async read on a tablespace which is being"
8161 << " deleted. Tablespace name: \"" << space->name << "\","
8162 << " page: " << page_id << ", read length: " << len << " bytes";
8163 }
8164 #ifndef UNIV_HOTBACKUP
8165 }
8166 #endif /* !UNIV_HOTBACKUP */
8167 }
8168 }
8169
8170 return DB_TABLESPACE_DELETED;
8171 }
8172
8173 #ifndef UNIV_HOTBACKUP
8174
2/2
✓ Branch 0 taken 77076127 times.
✓ Branch 1 taken 998276 times.
78074403 if (bpage != nullptr) {
8175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77076374 times.
77076127 ut_a(bpage->get_space()->id == page_id.space());
8176
8177
7/8
✓ Branch 0 taken 21192496 times.
✓ Branch 1 taken 55883857 times.
✓ Branch 2 taken 21192678 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 21192662 times.
✓ Branch 6 taken 16 times.
✓ Branch 7 taken 77076519 times.
77076374 if (req_type.is_write() && bpage->is_stale()) {
8178
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 mutex_release();
8179 16 return DB_PAGE_IS_STALE;
8180 }
8181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77076475 times.
77076519 ut_a(bpage->get_space() == space);
8182 }
8183 #endif /* !UNIV_HOTBACKUP */
8184
8185 fil_node_t *file;
8186 78074751 auto page_no = page_id.page_no();
8187
1/2
✓ Branch 0 taken 78074624 times.
✗ Branch 1 not taken.
78074524 auto err = get_file_for_io(space, &page_no, file);
8188
8189
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 78074383 times.
78074624 if (file == nullptr) {
8190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 241 times.
241 ut_ad(err == DB_ERROR);
8191
8192
1/2
✓ Branch 0 taken 241 times.
✗ Branch 1 not taken.
241 if (req_type.ignore_missing()) {
8193
1/2
✓ Branch 0 taken 241 times.
✗ Branch 1 not taken.
241 mutex_release();
8194
8195 241 return DB_ERROR;
8196 }
8197
8198 #ifndef UNIV_HOTBACKUP
8199 if (req_type.is_write() && bpage != nullptr && bpage->is_stale()) {
8200 ut_a(bpage->get_space()->id == page_id.space());
8201
8202 mutex_release();
8203 return DB_PAGE_IS_STALE;
8204 }
8205 #endif /* !UNIV_HOTBACKUP */
8206
8207 /* This is a hard error. */
8208 fil_report_invalid_page_access(page_id.page_no(), page_id.space(),
8209 space->name, byte_offset, len,
8210 req_type.is_read());
8211 }
8212
8213 #ifndef UNIV_HOTBACKUP
8214
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 78074253 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78074253 times.
78074253 if (UNIV_UNLIKELY(space->is_corrupt && srv_pass_corrupt_table)) {
8215 /* should ignore i/o for the crashed space */
8216 if (srv_pass_corrupt_table == 1 || req_type.is_write()) {
8217 complete_io(file, type);
8218 if (aio_mode == AIO_mode::NORMAL) {
8219 ut_a(space->purpose == FIL_TYPE_TABLESPACE);
8220 buf_page_io_complete(static_cast<buf_page_t *>(message), false);
8221 }
8222 }
8223
8224 if (srv_pass_corrupt_table == 1 && req_type.is_read())
8225 return (DB_TABLESPACE_DELETED);
8226 else if (req_type.is_write())
8227 return (DB_SUCCESS);
8228 }
8229 #endif
8230
8231
2/4
✓ Branch 0 taken 78074201 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 78074201 times.
78074253 if (!prepare_file_for_io(file)) {
8232 #ifndef UNIV_HOTBACKUP
8233 if (space->is_deleted()) {
8234 mutex_release();
8235
8236 if (!sync) {
8237 ut_d(bpage->take_io_responsibility());
8238 buf_page_io_complete(bpage, false);
8239 }
8240
8241 return DB_TABLESPACE_DELETED;
8242 }
8243 #endif /* !UNIV_HOTBACKUP */
8244
8245 if (fsp_is_ibd_tablespace(space->id)) {
8246 mutex_release();
8247
8248 if (!req_type.ignore_missing()) {
8249 ib::error(ER_IB_MSG_332)
8250 << "Trying to do I/O to a tablespace"
8251 " which exists without an .ibd data"
8252 << " file. I/O type: " << (req_type.is_read() ? "read" : "write")
8253 << ", page: " << page_id_t(page_id.space(), page_no)
8254 << ", I/O length: " << len << " bytes";
8255 }
8256
8257 return DB_TABLESPACE_DELETED;
8258 }
8259
8260 /* Could not open a file to perform IO and this is not a IBD file,
8261 which could have become deleted meanwhile. This is a fatal error.
8262 Note: any log information should be emitted inside prepare_file_for_io()
8263 called few lines earlier. That's because the specific reason for this
8264 problem is known only inside there. */
8265 ut_error;
8266 }
8267
8268 /* Check that at least the start offset is within the bounds of a
8269 single-table tablespace, including rollback tablespaces. */
8270
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 78074199 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
78074201 if (file->size <= page_no && space->id != TRX_SYS_SPACE) {
8271 #ifndef UNIV_HOTBACKUP
8272
2/10
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 if (req_type.is_write() && bpage != nullptr && bpage->is_stale()) {
8273 ut_a(bpage->get_space()->id == page_id.space());
8274 return DB_PAGE_IS_STALE;
8275 }
8276 #endif /* !UNIV_HOTBACKUP */
8277
8278
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (req_type.ignore_missing()) {
8279 /* If we can tolerate the non-existent pages, we
8280 should return with DB_ERROR and let caller decide
8281 what to do. */
8282
8283
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 complete_io(file, req_type);
8284
8285
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mutex_release();
8286
8287 2 return DB_ERROR;
8288 }
8289
8290 /* This is a hard error. */
8291 fil_report_invalid_page_access(page_id.page_no(), page_id.space(),
8292 space->name, byte_offset, len,
8293 req_type.is_read());
8294 }
8295
8296 /* Set encryption information. */
8297
1/2
✓ Branch 0 taken 78074119 times.
✗ Branch 1 not taken.
78074199 fil_io_set_encryption(req_type, page_id, space);
8298
8299
1/2
✓ Branch 0 taken 78074552 times.
✗ Branch 1 not taken.
78074119 mutex_release();
8300
8301
3/4
✓ Branch 0 taken 76429888 times.
✓ Branch 1 taken 1644664 times.
✓ Branch 2 taken 76429722 times.
✗ Branch 3 not taken.
78074552 DEBUG_SYNC_C("innodb_fil_do_io_prepared_io_with_no_mutex");
8302
8303
6/10
✓ Branch 0 taken 77956967 times.
✓ Branch 1 taken 117608 times.
✓ Branch 2 taken 77956819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 77956708 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 77956708 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 78074473 times.
78074386 ut_a(page_size.is_compressed() ||
8304 page_size.physical() == page_size.logical());
8305
8306
1/2
✓ Branch 0 taken 78074422 times.
✗ Branch 1 not taken.
78074473 auto offset = (os_offset_t)page_no * page_size.physical();
8307
8308 78074422 offset += byte_offset;
8309
8310
3/6
✓ Branch 0 taken 78074320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78074413 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 78074413 times.
78074422 ut_a(file->size - page_no >=
8311 (byte_offset +
8312 std::max(static_cast<uint32_t>(len), type.get_original_size()) +
8313 (page_size.physical() - 1)) /
8314 page_size.physical());
8315
8316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78074391 times.
78074413 ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
8317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78074229 times.
78074391 ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
8318
8319 /* Don't compress the log, page 0 of all tablespaces, tables compressed with
8320 the old compression scheme and all pages from the system tablespace. */
8321
4/4
✓ Branch 0 taken 21138625 times.
✓ Branch 1 taken 64999 times.
✓ Branch 2 taken 20437097 times.
✓ Branch 3 taken 701526 times.
120416467 if (req_type.is_write() && !page_size.is_compressed() &&
8322
6/8
✓ Branch 0 taken 21203615 times.
✓ Branch 1 taken 56870735 times.
✓ Branch 2 taken 20437162 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20437164 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20336459 times.
✓ Branch 7 taken 57737963 times.
140853761 page_id.page_no() > 0 && IORequest::is_punch_hole_supported() &&
8323
2/2
✓ Branch 0 taken 20336457 times.
✓ Branch 1 taken 100707 times.
20437164 file->punch_hole) {
8324
1/2
✓ Branch 0 taken 20336453 times.
✗ Branch 1 not taken.
20336459 req_type.set_punch_hole();
8325
8326
1/2
✓ Branch 0 taken 20336456 times.
✗ Branch 1 not taken.
20336453 req_type.compression_algorithm(space->compression_type);
8327
8328 } else {
8329 57737963 req_type.clear_compressed();
8330 }
8331
8332
2/2
✓ Branch 0 taken 117747 times.
✓ Branch 1 taken 77956818 times.
78074431 if (page_size.is_compressed()) {
8333 117747 req_type.mark_page_zip_compressed();
8334
1/2
✓ Branch 0 taken 117747 times.
✗ Branch 1 not taken.
117747 req_type.set_zip_page_physical_size(page_size.physical());
8335
2/4
✓ Branch 0 taken 117747 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 117747 times.
117747 ut_ad(page_size.physical() > 0);
8336 }
8337
8338 78074565 req_type.block_size(file->block_size);
8339
8340 #ifdef UNIV_HOTBACKUP
8341 /* In mysqlbackup do normal I/O, not AIO */
8342 if (req_type.is_read()) {
8343 err = os_file_read(req_type, file->name, file->handle, buf, offset, len);
8344
8345 } else {
8346 ut_ad(!srv_read_only_mode || fsp_is_system_temporary(page_id.space()));
8347
8348 err = os_file_write(req_type, file->name, file->handle, buf, offset, len);
8349 }
8350 #else /* UNIV_HOTBACKUP */
8351 /* Queue the aio request */
8352
4/6
✓ Branch 0 taken 78074506 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7993691 times.
✓ Branch 3 taken 70080815 times.
✓ Branch 4 taken 78073760 times.
✗ Branch 5 not taken.
78074449 err = os_aio(
8353 req_type, aio_mode, file->name, file->handle, buf, offset, len,
8354 fsp_is_system_temporary(page_id.space()) ? false : srv_read_only_mode,
8355 file, message, page_id.space(), trx, should_buffer);
8356
8357 #endif /* UNIV_HOTBACKUP */
8358
8359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78073760 times.
78073760 if (err == DB_IO_NO_PUNCH_HOLE) {
8360 err = DB_SUCCESS;
8361
8362 if (file->punch_hole) {
8363 ib::warn(ER_IB_MSG_333) << "Punch hole failed for '" << file->name << "'";
8364 }
8365
8366 fil_no_punch_hole(file);
8367 }
8368
8369 /* We an try to recover the page from the double write buffer if
8370 the decompression fails or the page is corrupt. */
8371
8372
4/8
✓ Branch 0 taken 77097351 times.
✓ Branch 1 taken 975987 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 77097351 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 78073626 times.
78073760 ut_a(req_type.is_dblwr() || err == DB_SUCCESS || err == DB_IO_DECRYPT_FAIL);
8373
8374
2/2
✓ Branch 0 taken 55975644 times.
✓ Branch 1 taken 22097982 times.
78073626 if (sync) {
8375 /* The i/o operation is already completed when we return from
8376 os_aio: */
8377
8378
1/2
✓ Branch 0 taken 55976199 times.
✗ Branch 1 not taken.
55975644 mutex_acquire();
8379
8380
1/2
✓ Branch 0 taken 55976215 times.
✗ Branch 1 not taken.
55976199 complete_io(file, req_type);
8381
8382
1/2
✓ Branch 0 taken 55976162 times.
✗ Branch 1 not taken.
55976215 mutex_release();
8383
8384
2/4
✓ Branch 0 taken 55976149 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 55976408 times.
55976162 ut_ad(fil_validate_skip());
8385 }
8386
8387 78074390 return err;
8388 78075582 }
8389
8390 #ifndef UNIV_HOTBACKUP
8391 /** Waits for an AIO operation to complete. This function is used to write the
8392 handler for completed requests. The aio array of pending requests is divided
8393 into segments (see os0file.cc for more info). The thread specifies which
8394 segment it wants to wait for.
8395 @param[in] segment The number of the segment in the AIO array
8396 to wait for */
8397 22320762 void fil_aio_wait(ulint segment) {
8398 void *m2;
8399 fil_node_t *m1;
8400 22320762 IORequest type;
8401
8402
2/4
✓ Branch 0 taken 22321116 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22321173 times.
22321375 ut_ad(fil_validate_skip());
8403
8404
1/2
✓ Branch 0 taken 22306865 times.
✗ Branch 1 not taken.
22321173 auto err = os_aio_handler(segment, &m1, &m2, &type);
8405
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 22307278 times.
22306865 ut_a(err == DB_SUCCESS);
8406
8407 22307278 auto file = reinterpret_cast<fil_node_t *>(m1);
8408
8409
2/2
✓ Branch 0 taken 208875 times.
✓ Branch 1 taken 22098403 times.
22307278 if (file == nullptr) {
8410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208698 times.
208875 ut_ad(srv_shutdown_state.load() == SRV_SHUTDOWN_EXIT_THREADS);
8411 208698 return;
8412 }
8413
8414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22098306 times.
22098403 ut_a(!type.is_dblwr());
8415
8416
1/2
✓ Branch 0 taken 22098400 times.
✗ Branch 1 not taken.
22098306 srv_set_io_thread_op_info(segment, "complete io for file");
8417
8418
1/2
✓ Branch 0 taken 22098373 times.
✗ Branch 1 not taken.
22098400 auto shard = fil_system->shard_by_id(file->space->id);
8419
8420
1/2
✓ Branch 0 taken 22098353 times.
✗ Branch 1 not taken.
22098373 shard->mutex_acquire();
8421
8422
1/2
✓ Branch 0 taken 22098384 times.
✗ Branch 1 not taken.
22098353 shard->complete_io(file, type);
8423
8424
1/2
✓ Branch 0 taken 22098360 times.
✗ Branch 1 not taken.
22098384 shard->mutex_release();
8425
8426
2/4
✓ Branch 0 taken 22098260 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22098306 times.
22098360 ut_ad(fil_validate_skip());
8427
8428 /* Do the i/o handling */
8429 /* IMPORTANT: since i/o handling for reads will read also the insert
8430 buffer in tablespace 0, you have to be very careful not to introduce
8431 deadlocks in the i/o system. We keep tablespace 0 data files always
8432 open, and use a special i/o thread to serve insert buffer requests. */
8433
8434
1/2
✓ Branch 0 taken 22098306 times.
✗ Branch 1 not taken.
22098306 switch (file->space->purpose) {
8435 22098306 case FIL_TYPE_IMPORT:
8436 case FIL_TYPE_TEMPORARY:
8437 case FIL_TYPE_TABLESPACE:
8438
1/2
✓ Branch 0 taken 22098222 times.
✗ Branch 1 not taken.
22098306 srv_set_io_thread_op_info(segment, "complete io for buf page");
8439
8440 /* async single page writes from the dblwr buffer don't have
8441 access to the page */
8442
1/2
✓ Branch 0 taken 22098245 times.
✗ Branch 1 not taken.
22098222 if (m2 != nullptr) {
8443 22098245 auto bpage = static_cast<buf_page_t *>(m2);
8444
1/2
✓ Branch 0 taken 22098085 times.
✗ Branch 1 not taken.
22098245 ut_d(bpage->take_io_responsibility());
8445
1/2
✓ Branch 0 taken 22097456 times.
✗ Branch 1 not taken.
22098085 buf_page_io_complete(bpage, false);
8446 }
8447 22097433 return;
8448 }
8449
8450 ut_d(ut_error);
8451 22306131 }
8452 #endif /* !UNIV_HOTBACKUP */
8453
8454 /** Read or write data from a file.
8455 @param[in] type IO context
8456 @param[in] sync If true then do synchronous IO
8457 @param[in] page_id page id
8458 @param[in] page_size page size
8459 @param[in] byte_offset remainder of offset in bytes; in aio this
8460 must be divisible by the OS block size
8461 @param[in] len how many bytes to read or write; this must
8462 not cross a file boundary; in AIO this must
8463 be a block size multiple
8464 @param[in,out] buf buffer where to store read data or from where
8465 to write; in AIO this must be appropriately
8466 aligned
8467 @param[in] message message for AIO handler if !sync, else ignored
8468 @param[in] should_buffer whether to buffer an aio request. AIO read
8469 ahead uses this. If you plan to use this
8470 parameter, make sure you remember to call
8471 os_aio_dispatch_read_array_submit() when you're
8472 ready to commit all your requests.
8473 @return error code
8474 @retval DB_SUCCESS on success
8475 @retval DB_TABLESPACE_DELETED if the tablespace does not exist */
8476 78074012 dberr_t _fil_io(const IORequest &type, bool sync, const page_id_t &page_id,
8477 const page_size_t &page_size, ulint byte_offset, ulint len,
8478 void *buf, void *message, trx_t *trx, bool should_buffer) {
8479 78074012 auto shard = fil_system->shard_by_id(page_id.space());
8480 #ifdef UNIV_DEBUG
8481
2/2
✓ Branch 0 taken 22099106 times.
✓ Branch 1 taken 55976072 times.
78075178 if (!sync) {
8482 /* In case of async io we transfer the io responsibility to the thread which
8483 will perform the io completion routine. */
8484 22099106 static_cast<buf_page_t *>(message)->release_io_responsibility();
8485 }
8486 #endif
8487
8488 78075231 auto const err = shard->do_io(type, sync, page_id, page_size, byte_offset,
8489 len, buf, message, trx, should_buffer);
8490 #ifdef UNIV_DEBUG
8491 /* If the error prevented async io, then we haven't actually transfered the
8492 io responsibility at all, so we revert the debug io responsibility info. */
8493 78075086 auto bpage = static_cast<buf_page_t *>(message);
8494
8495 /* When space is deleted, we could have marked the io complete. */
8496
7/8
✓ Branch 0 taken 1192 times.
✓ Branch 1 taken 78073894 times.
✓ Branch 2 taken 949 times.
✓ Branch 3 taken 243 times.
✓ Branch 4 taken 949 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 949 times.
✓ Branch 7 taken 78074137 times.
78075086 if (err != DB_SUCCESS && !sync && bpage->was_io_fixed()) {
8497 949 bpage->take_io_responsibility();
8498 }
8499 #endif
8500 78075593 return err;
8501 }
8502
8503 /** If the tablespace is on the unflushed list and there are no pending
8504 flushes then remove from the unflushed list.
8505 @param[in,out] space Tablespace to remove */
8506 10775146 void Fil_shard::remove_from_unflushed_list(fil_space_t *space) {
8507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10775588 times.
10775146 ut_ad(mutex_owned());
8508
8509
6/6
✓ Branch 0 taken 10775102 times.
✓ Branch 1 taken 486 times.
✓ Branch 2 taken 9988067 times.
✓ Branch 3 taken 786770 times.
✓ Branch 4 taken 9988061 times.
✓ Branch 5 taken 787262 times.
10775588 if (space->is_in_unflushed_spaces && space_is_flushed(space)) {
8510 9988061 space->is_in_unflushed_spaces = false;
8511
8512 9988061 UT_LIST_REMOVE(m_unflushed_spaces, space);
8513 }
8514 10775715 }
8515
8516 11126217 void Fil_shard::space_flush(space_id_t space_id) {
8517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11126221 times.
11126217 ut_ad(mutex_owned());
8518
8519 11126221 fil_space_t *space = get_space_by_id(space_id);
8520
8521
4/4
✓ Branch 0 taken 11126203 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 11026212 times.
✓ Branch 3 taken 99991 times.
11126216 if (space == nullptr || space->purpose == FIL_TYPE_TEMPORARY ||
8522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11026212 times.
11026212 space->stop_new_ops) {
8523 100004 return;
8524 }
8525
8526 11026212 const bool disable_flush = fil_disable_space_flushing(space);
8527
8528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11026201 times.
11026201 if (disable_flush) {
8529 /* No need to flush. User has explicitly disabled
8530 buffering. However, flush should be called if the file
8531 size changes to keep OÐ… metadata in sync. */
8532 ut_ad(!space->is_in_unflushed_spaces);
8533 ut_ad(space_is_flushed(space));
8534
8535 /* Flush only if the file size changes */
8536 bool no_flush = true;
8537 for (const auto &file : space->files) {
8538 #ifdef UNIV_DEBUG
8539 ut_ad(file.is_flushed());
8540 #endif /* UNIV_DEBUG */
8541 if (file.flush_size != file.size) {
8542 /* Found at least one file whose size has changed */
8543 no_flush = false;
8544 break;
8545 }
8546 }
8547
8548 if (no_flush) {
8549 /* Nothing to flush. Just return */
8550 return;
8551 }
8552 }
8553
8554 /* Prevent dropping of the space while we are flushing */
8555 11026201 ++space->n_pending_flushes;
8556
8557
2/2
✓ Branch 0 taken 11029101 times.
✓ Branch 1 taken 11025895 times.
22055117 for (auto &file : space->files) {
8558 11029149 int64_t old_mod_counter = file.modification_counter;
8559
8560
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 11028817 times.
11029149 if (!file.is_open) {
8561 332 continue;
8562 }
8563
8564 /* Skip flushing if the file size has not changed since
8565 last flush was done and the flush mode is O_DIRECT_NO_FSYNC */
8566
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11028817 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
11028817 if (disable_flush && (file.flush_size == file.size)) {
8567 ut_ad(old_mod_counter <= file.flush_counter);
8568 continue;
8569 }
8570
8571 /* If we are here and the flush mode is O_DIRECT_NO_FSYNC, then
8572 it means that the file size has changed and hence, it should be
8573 flushed, irrespective of the mod_counter and flush counter values,
8574 which are always same in case of O_DIRECT_NO_FSYNC to avoid flush
8575 on every write operation.
8576 For other flush modes, if the flush_counter is same or ahead of
8577 the mod_counter, skip the flush. */
8578
3/4
✓ Branch 0 taken 11028821 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9992 times.
✓ Branch 3 taken 11018829 times.
11028817 if (!disable_flush && (old_mod_counter <= file.flush_counter)) {
8579 9992 continue;
8580 }
8581
8582
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 11018821 times.
✓ Branch 2 taken 4 times.
11018825 switch (space->purpose) {
8583 case FIL_TYPE_TEMPORARY:
8584 ut_error; // we already checked for this
8585
8586 11018821 case FIL_TYPE_TABLESPACE:
8587 case FIL_TYPE_IMPORT:
8588 11018821 ++fil_n_pending_tablespace_flushes;
8589 11018821 break;
8590 }
8591
8592 11018825 bool skip_flush = is_fast_shutdown();
8593 #ifdef _WIN32
8594 if (file.is_raw_disk) {
8595 skip_flush |= true;
8596 }
8597 #endif /* _WIN32 */
8598
8599
4/4
✓ Branch 0 taken 385159 times.
✓ Branch 1 taken 11017027 times.
✓ Branch 2 taken 383376 times.
✓ Branch 3 taken 1783 times.
11402186 while (file.n_pending_flushes > 0 && !skip_flush) {
8600 /* We want to avoid calling os_file_flush() on
8601 the file twice at the same time, because we do
8602 not know what bugs OS's may contain in file
8603 I/O */
8604
8605
1/2
✓ Branch 0 taken 383376 times.
✗ Branch 1 not taken.
383376 int64_t sig_count = os_event_reset(file.sync_event);
8606
8607
1/2
✓ Branch 0 taken 383376 times.
✗ Branch 1 not taken.
383376 mutex_release();
8608
8609
1/2
✓ Branch 0 taken 383372 times.
✗ Branch 1 not taken.
383376 os_event_wait_low(file.sync_event, sig_count);
8610
8611
1/2
✓ Branch 0 taken 383376 times.
✗ Branch 1 not taken.
383372 mutex_acquire();
8612
8613
2/2
✓ Branch 0 taken 242948 times.
✓ Branch 1 taken 140428 times.
383376 if (file.flush_counter >= old_mod_counter) {
8614 242948 skip_flush |= true;
8615 }
8616 383376 skip_flush |= is_fast_shutdown();
8617 }
8618
8619
2/2
✓ Branch 0 taken 10775845 times.
✓ Branch 1 taken 242965 times.
11018810 if (!skip_flush) {
8620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10775844 times.
10775845 ut_a(file.is_open);
8621 10775844 ++file.n_pending_flushes;
8622
8623
1/2
✓ Branch 0 taken 10775874 times.
✗ Branch 1 not taken.
10775844 mutex_release();
8624
8625
1/2
✓ Branch 0 taken 10774915 times.
✗ Branch 1 not taken.
10775874 os_file_flush(file.handle);
8626
8627 10774915 file.flush_size = file.size;
8628
8629
1/2
✓ Branch 0 taken 10775019 times.
✗ Branch 1 not taken.
10774915 mutex_acquire();
8630
8631
1/2
✓ Branch 0 taken 10775669 times.
✗ Branch 1 not taken.
10775019 os_event_set(file.sync_event);
8632
8633 10775669 --file.n_pending_flushes;
8634 }
8635
8636
2/2
✓ Branch 0 taken 10775663 times.
✓ Branch 1 taken 242971 times.
11018634 if (file.flush_counter < old_mod_counter) {
8637 10775663 file.flush_counter = old_mod_counter;
8638
8639
1/2
✓ Branch 0 taken 10775621 times.
✗ Branch 1 not taken.
10775663 remove_from_unflushed_list(space);
8640 }
8641
8642
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 11018592 times.
✗ Branch 2 not taken.
11018592 switch (space->purpose) {
8643 case FIL_TYPE_TEMPORARY:
8644 ut_error; // we already checked for this
8645
8646 11018592 case FIL_TYPE_TABLESPACE:
8647 case FIL_TYPE_IMPORT:
8648 11018592 --fil_n_pending_tablespace_flushes;
8649 11018592 continue;
8650 }
8651
8652 ut_d(ut_error);
8653 }
8654
8655 11025895 --space->n_pending_flushes;
8656 }
8657
8658 162574 void fil_flush(space_id_t space_id) {
8659 162574 auto shard = fil_system->shard_by_id(space_id);
8660
8661 162574 shard->mutex_acquire();
8662
8663 /* Note: Will release and reacquire the Fil_shard::mutex. */
8664 162574 shard->space_flush(space_id);
8665
8666 162574 shard->mutex_release();
8667 162574 }
8668
8669 498439398 void Fil_shard::flush_file_spaces() {
8670
1/2
✓ Branch 0 taken 498457905 times.
✗ Branch 1 not taken.
498439398 Space_ids space_ids;
8671
8672
1/2
✓ Branch 0 taken 498490286 times.
✗ Branch 1 not taken.
498457905 mutex_acquire();
8673
8674
6/10
✓ Branch 0 taken 498489470 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 498472929 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10664800 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 509140060 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10664809 times.
✓ Branch 9 taken 498475251 times.
509155093 for (auto space : m_unflushed_spaces) {
8675
4/4
✓ Branch 0 taken 10664769 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 10663879 times.
✓ Branch 3 taken 929 times.
21329577 if ((to_int(space->purpose) & FIL_TYPE_TABLESPACE) &&
8676
2/2
✓ Branch 0 taken 10663879 times.
✓ Branch 1 taken 890 times.
10664769 !space->stop_new_ops) {
8677
1/2
✓ Branch 0 taken 10663878 times.
✗ Branch 1 not taken.
10663879 space_ids.push_back(space->id);
8678 }
8679 }
8680
8681
1/2
✓ Branch 0 taken 498521911 times.
✗ Branch 1 not taken.
498475251 mutex_release();
8682
8683 /* Flush the spaces. It will not hurt to call fil_flush() on
8684 a non-existing space id. */
8685
2/2
✓ Branch 0 taken 10663877 times.
✓ Branch 1 taken 498444514 times.
509185194 for (auto space_id : space_ids) {
8686
1/2
✓ Branch 0 taken 10663879 times.
✗ Branch 1 not taken.
10663875 mutex_acquire();
8687
8688
1/2
✓ Branch 0 taken 10663025 times.
✗ Branch 1 not taken.
10663879 space_flush(space_id);
8689
8690
1/2
✓ Branch 0 taken 10663283 times.
✗ Branch 1 not taken.
10663025 mutex_release();
8691 }
8692 498444514 }
8693
8694 7331668 void Fil_system::flush_file_spaces() {
8695
2/2
✓ Branch 0 taken 498439817 times.
✓ Branch 1 taken 7328180 times.
505778243 for (auto shard : m_shards) {
8696
1/2
✓ Branch 0 taken 498446575 times.
✗ Branch 1 not taken.
498439847 shard->flush_file_spaces();
8697 }
8698 7328180 }
8699
8700 7315301 void fil_flush_file_spaces() { fil_system->flush_file_spaces(); }
8701
8702 /** Returns true if file address is undefined.
8703 @param[in] addr File address to check
8704 @return true if undefined */
8705 20734116 bool fil_addr_is_null(const fil_addr_t &addr) {
8706 20734116 return (addr.page == FIL_NULL);
8707 }
8708
8709 /** Get the predecessor of a file page.
8710 @param[in] page File page
8711 @return FIL_PAGE_PREV */
8712 10781840 page_no_t fil_page_get_prev(const byte *page) {
8713 10781840 return mach_read_from_4(page + FIL_PAGE_PREV);
8714 }
8715
8716 /** Get the successor of a file page.
8717 @param[in] page File page
8718 @return FIL_PAGE_NEXT */
8719 10786161 page_no_t fil_page_get_next(const byte *page) {
8720 10786161 return mach_read_from_4(page + FIL_PAGE_NEXT);
8721 }
8722
8723 /** Sets the file page type.
8724 @param[in,out] page File page
8725 @param[in] type File page type to set */
8726 3406860 void fil_page_set_type(byte *page, ulint type) {
8727 3406860 mach_write_to_2(page + FIL_PAGE_TYPE, type);
8728 3406861 }
8729
8730 /** Reset the page type.
8731 Data files created before MySQL 5.1 may contain garbage in FIL_PAGE_TYPE.
8732 In MySQL 3.23.53, only undo log pages and index pages were tagged.
8733 Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE.
8734 @param[in] page_id Page number
8735 @param[in,out] page Page with invalid FIL_PAGE_TYPE
8736 @param[in] type Expected page type
8737 @param[in,out] mtr Mini-transaction */
8738 1 void fil_page_reset_type(const page_id_t &page_id, byte *page, ulint type,
8739 mtr_t *mtr) {
8740
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 ib::info(ER_IB_MSG_334) << "Resetting invalid page " << page_id << " type "
8741
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 << fil_page_get_type(page) << " to " << type << ".";
8742 1 mlog_write_ulint(page + FIL_PAGE_TYPE, type, MLOG_2BYTES, mtr);
8743 1 }
8744
8745 /** Closes the tablespace memory cache. */
8746 10639 void fil_close() {
8747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10639 times.
10639 if (fil_system == nullptr) {
8748 return;
8749 }
8750
8751 10639 ut::delete_(fil_system);
8752
8753 10639 fil_system = nullptr;
8754 10639 fil_space_crypt_cleanup();
8755 }
8756
8757 #ifndef UNIV_HOTBACKUP
8758 /** Initializes the buffer control block used by fil_tablespace_iterate.
8759 @param[in] block Pointer to the control block
8760 @param[in] frame Pointer to buffer frame */
8761 700 static void fil_buf_block_init(buf_block_t *block, byte *frame) {
8762 UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE);
8763
8764 700 block->frame = frame;
8765
8766 700 block->page.init_io_fix();
8767 /* There are assertions that check for this. */
8768 700 block->page.buf_fix_count.store(1);
8769 700 block->page.state = BUF_BLOCK_READY_FOR_USE;
8770
8771 700 page_zip_des_init(&block->page.zip);
8772 700 }
8773
8774 struct Fil_page_iterator {
8775 /** File handle */
8776 pfs_os_file_t m_file;
8777
8778 /** File path name */
8779 const char *m_filepath;
8780
8781 /** From where to start */
8782 os_offset_t m_start;
8783
8784 /** Where to stop */
8785 os_offset_t m_end;
8786
8787 /* File size in bytes */
8788 os_offset_t m_file_size;
8789
8790 /** Page size */
8791 size_t m_page_size;
8792
8793 /** Number of pages to use for I/O */
8794 size_t m_n_io_buffers;
8795
8796 /** Buffer to use for IO */
8797 byte *m_io_buffer;
8798
8799 /** Encryption key */
8800 byte *m_encryption_key;
8801
8802 /** Encruption iv */
8803 byte *m_encryption_iv;
8804
8805 uint m_encryption_key_version;
8806 uint m_encryption_key_id;
8807 fil_space_crypt_t *m_crypt_data; /*!< Crypt data (if encrypted) */
8808
8809 /** FS Block Size */
8810 size_t block_size;
8811
8812 /** Compression algorithm to be used if the table needs to be compressed. */
8813 Compression::Type m_compression_type{};
8814 };
8815
8816 /** TODO: This can be made parallel trivially by chunking up the file
8817 and creating a callback per thread. Main benefit will be to use multiple
8818 CPUs for checksums and compressed tables. We have to do compressed tables
8819 block by block right now. Secondly we need to decompress/compress and copy
8820 too much of data. These are CPU intensive.
8821
8822 Iterate over all the pages in the tablespace.
8823 @param[in] iter Tablespace iterator
8824 @param[in,out] block Block to use for IO
8825 @param[in] callback Callback to inspect and update page contents
8826 @retval DB_SUCCESS or error code */
8827 680 static dberr_t fil_iterate(const Fil_page_iterator &iter, buf_block_t *block,
8828 PageCallback &callback) {
8829 os_offset_t offset;
8830 size_t n_bytes;
8831 680 page_no_t page_no = 0;
8832 680 space_id_t space_id = callback.get_space_id();
8833
8834 680 n_bytes = iter.m_n_io_buffers * iter.m_page_size;
8835
8836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 680 times.
680 ut_ad(!srv_read_only_mode);
8837
8838 /* For old style compressed tables we do a lot of useless copying
8839 for non-index pages. Unfortunately, it is required by
8840 buf_zip_decompress() */
8841
8842 680 ulint read_type = IORequest::READ;
8843 680 ulint write_type = IORequest::WRITE;
8844
8845
2/2
✓ Branch 0 taken 55882 times.
✓ Branch 1 taken 654 times.
56536 for (offset = iter.m_start; offset < iter.m_end; offset += n_bytes) {
8846
1/2
✓ Branch 0 taken 55882 times.
✗ Branch 1 not taken.
55882 IORequest read_request(read_type);
8847
8848 55882 byte *io_buffer = iter.m_io_buffer;
8849
8850 55882 block->frame = io_buffer;
8851
8852
2/2
✓ Branch 0 taken 3871 times.
✓ Branch 1 taken 52011 times.
55882 if (callback.get_page_size().is_compressed()) {
8853 3871 page_zip_des_init(&block->page.zip);
8854
1/2
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
3871 page_zip_set_size(&block->page.zip, iter.m_page_size);
8855
8856
1/2
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
3871 block->page.size.copy_from(
8857 page_size_t(static_cast<uint32_t>(iter.m_page_size),
8858
2/4
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3871 times.
✗ Branch 3 not taken.
3871 static_cast<uint32_t>(univ_page_size.logical()), true));
8859
8860 3871 block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
8861 3871 ut_d(block->page.zip.m_external = true);
8862
2/4
✓ Branch 0 taken 3871 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3871 times.
3871 ut_ad(iter.m_page_size == callback.get_page_size().physical());
8863
8864 3871 read_request.mark_page_zip_compressed();
8865 3871 read_request.set_zip_page_physical_size(iter.m_page_size);
8866
8867 /* Zip IO is done in the compressed page buffer. */
8868 3871 io_buffer = block->page.zip.data;
8869 } else {
8870 52011 io_buffer = iter.m_io_buffer;
8871 }
8872
8873 /* We have to read the exact number of bytes. Otherwise the
8874 InnoDB IO functions croak on failed reads. */
8875
8876 55882 n_bytes = static_cast<ulint>(
8877 55882 std::min(static_cast<os_offset_t>(n_bytes), iter.m_end - offset));
8878
8879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55882 times.
55882 ut_ad(n_bytes > 0);
8880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55882 times.
55882 ut_ad(!(n_bytes % iter.m_page_size));
8881
8882 55882 const bool encrypted_with_keyring =
8883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55882 times.
55882 iter.m_crypt_data != NULL &&
8884 iter.m_crypt_data->type != CRYPT_SCHEME_UNENCRYPTED;
8885 dberr_t err;
8886 55882 read_request.block_size(iter.block_size);
8887
8888 /* For encrypted table, set encryption information. */
8889
8890
5/6
✓ Branch 0 taken 36128 times.
✓ Branch 1 taken 19754 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36128 times.
✓ Branch 4 taken 19599 times.
✓ Branch 5 taken 155 times.
55882 if ((iter.m_encryption_key != NULL || encrypted_with_keyring) &&
8891 offset != 0) {
8892
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 19599 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19599 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 19599 times.
✓ Branch 6 taken 19599 times.
✗ Branch 7 not taken.
39198 read_request.encryption_key(
8893 encrypted_with_keyring ? iter.m_crypt_data->tablespace_key
8894 : iter.m_encryption_key,
8895 Encryption::KEY_LEN,
8896 encrypted_with_keyring ? iter.m_crypt_data->iv : iter.m_encryption_iv,
8897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19599 times.
19599 0, iter.m_encryption_key_id,
8898 encrypted_with_keyring ? iter.m_crypt_data->tablespace_key : nullptr,
8899 encrypted_with_keyring ? iter.m_crypt_data->uuid : nullptr, nullptr);
8900
8901
1/2
✓ Branch 0 taken 19599 times.
✗ Branch 1 not taken.
19599 read_request.encryption_algorithm(Encryption::AES);
8902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19599 times.
19599 if (iter.m_crypt_data) {
8903 read_request.encryption_rotation(
8904 iter.m_crypt_data->encryption_rotation);
8905 } else
8906
1/2
✓ Branch 0 taken 19599 times.
✗ Branch 1 not taken.
19599 read_request.encryption_rotation(Encryption_rotation::NO_ROTATION);
8907 }
8908
8909
1/2
✓ Branch 0 taken 55862 times.
✗ Branch 1 not taken.
55882 err = os_file_read(read_request, iter.m_filepath, iter.m_file, io_buffer,
8910 offset, (ulint)n_bytes);
8911
8912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55862 times.
55862 if (err != DB_SUCCESS) {
8913 ib::error(ER_IB_MSG_335) << "os_file_read() failed";
8914
8915 return err;
8916 }
8917
8918 size_t n_pages_read;
8919 55862 bool updated = false;
8920 55862 os_offset_t page_off = offset;
8921
8922 55862 n_pages_read = (ulint)n_bytes / iter.m_page_size;
8923
8924
2/2
✓ Branch 0 taken 55862 times.
✓ Branch 1 taken 55856 times.
111718 for (size_t i = 0; i < n_pages_read; ++i) {
8925
1/2
✓ Branch 0 taken 55862 times.
✗ Branch 1 not taken.
55862 buf_block_set_file_page(block, page_id_t(space_id, page_no++));
8926
8927 /* We are going to modify the page. Add to page tracking system. */
8928
1/2
✓ Branch 0 taken 55862 times.
✗ Branch 1 not taken.
55862 arch_page_sys->track_page(&block->page, LSN_MAX, LSN_MAX, true);
8929
8930
3/4
✓ Branch 0 taken 55862 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 55856 times.
55862 if ((err = callback(page_off, block)) != DB_SUCCESS) {
8931 6 return err;
8932
8933
1/2
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
55856 } else if (!updated) {
8934
1/2
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
55856 updated = buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE;
8935 }
8936
8937
1/2
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
55856 buf_block_set_state(block, BUF_BLOCK_NOT_USED);
8938
1/2
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
55856 buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
8939
8940 55856 page_off += iter.m_page_size;
8941 55856 block->frame += iter.m_page_size;
8942 }
8943
8944
1/2
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
55856 IORequest write_request(write_type);
8945 55856 write_request.block_size(iter.block_size);
8946
8947 /* For encrypted table, set encryption information. */
8948
4/4
✓ Branch 0 taken 19734 times.
✓ Branch 1 taken 36122 times.
✓ Branch 2 taken 19579 times.
✓ Branch 3 taken 155 times.
55856 if (iter.m_encryption_key != NULL && offset != 0 &&
8949
1/2
✓ Branch 0 taken 19579 times.
✗ Branch 1 not taken.
19579 iter.m_crypt_data == NULL) {
8950 19579 write_request.encryption_key(
8951 19579 iter.m_encryption_key, Encryption::KEY_LEN, iter.m_encryption_iv,
8952
1/2
✓ Branch 0 taken 19579 times.
✗ Branch 1 not taken.
19579 iter.m_encryption_key_version, iter.m_encryption_key_id, nullptr,
8953 nullptr, nullptr);
8954
1/2
✓ Branch 0 taken 19579 times.
✗ Branch 1 not taken.
19579 write_request.encryption_algorithm(Encryption::AES);
8955
3/4
✓ Branch 0 taken 35600 times.
✓ Branch 1 taken 677 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35600 times.
36277 } else if (offset != 0 && iter.m_crypt_data) {
8956 write_request.encryption_key(
8957 iter.m_encryption_key, Encryption::KEY_LEN, iter.m_encryption_iv,
8958 iter.m_encryption_key_version, iter.m_crypt_data->key_id, nullptr,
8959 iter.m_crypt_data->uuid, nullptr);
8960
8961 write_request.encryption_algorithm(Encryption::KEYRING);
8962
8963 if (callback.get_page_size().is_compressed()) {
8964 write_request.mark_page_zip_compressed();
8965 write_request.set_zip_page_physical_size(iter.m_page_size);
8966 }
8967 }
8968
8969 /* For compressed table, set compressed information.
8970 @note os_file_compress_page() function expects that the page size is a
8971 multiple of OS punch hole size so we make sure it's true before turning
8972 on compression. */
8973 113632 if (iter.m_compression_type != Compression::Type::NONE &&
8974
6/8
✓ Branch 0 taken 1920 times.
✓ Branch 1 taken 53936 times.
✓ Branch 2 taken 1920 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1920 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1920 times.
✓ Branch 7 taken 53936 times.
57776 IORequest::is_punch_hole_supported() &&
8975
1/2
✓ Branch 0 taken 1920 times.
✗ Branch 1 not taken.
1920 !(srv_page_size % iter.block_size)) {
8976
1/2
✓ Branch 0 taken 1920 times.
✗ Branch 1 not taken.
1920 write_request.compression_algorithm(iter.m_compression_type);
8977
8978 /* In the case of import since we're doing compression for the first time
8979 we would like to ignore any optimisations to not do punch hole. So force
8980 the punch hole. */
8981
1/2
✓ Branch 0 taken 1920 times.
✗ Branch 1 not taken.
1920 write_request.disable_punch_hole_optimisation();
8982 }
8983
8984 /* A page was updated in the set, write back to disk. */
8985
8986
4/8
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55856 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 55856 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 55856 times.
55856 if (updated && (err = os_file_write(write_request, iter.m_filepath,
8987 iter.m_file, io_buffer, offset,
8988 (ulint)n_bytes)) != DB_SUCCESS) {
8989 /* This is not a hard error */
8990 if (err == DB_IO_NO_PUNCH_HOLE) {
8991 err = DB_SUCCESS;
8992 write_type &= ~IORequest::PUNCH_HOLE;
8993
8994 } else {
8995 ib::error(ER_IB_MSG_336) << "os_file_write() failed";
8996
8997 return err;
8998 }
8999 }
9000
3/4
✓ Branch 0 taken 55856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55856 times.
✓ Branch 3 taken 6 times.
55862 }
9001
9002 654 return DB_SUCCESS;
9003 }
9004
9005 1693 void fil_adjust_name_import(dict_table_t *table [[maybe_unused]],
9006 const char *path,
9007 ib_file_suffix extn [[maybe_unused]]) {
9008 /* Try to open with current name first. */
9009
3/4
✓ Branch 0 taken 1693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1574 times.
✓ Branch 3 taken 119 times.
1693 if (os_file_exists(path)) {
9010 1574 return;
9011 }
9012
9013 /* On failure we need to check if file exists in different letter case
9014 for partitioned table. */
9015
9016 /* Safe check. Never needed on Windows. */
9017 #ifndef _WIN32
9018 /* Needed only for case sensitive file system. */
9019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
119 if (lower_case_file_system) {
9020 return;
9021 }
9022
9023 /* Only needed for partition file. */
9024
4/6
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 77 times.
✓ Branch 5 taken 42 times.
119 if (!dict_name::is_partition(table->name.m_name)) {
9025 77 return;
9026 }
9027
9028 /* Get Import directory path. */
9029
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 std::string import_dir(path);
9030 42 Fil_path::normalize(import_dir);
9031
9032 42 auto pos = import_dir.find_last_of(Fil_path::SEPARATOR);
9033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (pos == std::string::npos) {
9034 import_dir.assign(Fil_path::DOT_SLASH);
9035
9036 } else {
9037
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 import_dir.resize(pos + 1);
9038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 ut_ad(Fil_path::is_separator(import_dir.back()));
9039 }
9040
9041 /* Walk through all files under the directory and match the import file
9042 after adjusting case. This is a safe check to allow files exported from
9043 earlier versions where the case for partition name and separator could
9044 be different. */
9045 42 bool found_path = false;
9046 42 std::string saved_path;
9047
9048
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 Dir_Walker::walk(import_dir, false, [&](const std::string &file_path) {
9049 /* Skip entry if already found. */
9050
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 267 times.
549 if (found_path) {
9051 519 return;
9052 }
9053 /* Check only for partition files. */
9054
3/4
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 259 times.
267 if (!dict_name::is_partition(file_path)) {
9055 8 return;
9056 }
9057
9058 /* Extract table name from path. */
9059 259 std::string table_name;
9060
3/4
✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
✓ Branch 3 taken 111 times.
259 if (!Fil_path::parse_file_path(file_path, extn, table_name)) {
9061 /* Not a valid file-per-table path */
9062 148 return;
9063 }
9064
9065 /* Check if the file name would match after correcting the case. */
9066
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 dict_name::rebuild(table_name);
9067
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 30 times.
111 if (table_name.compare(table->name.m_name) != 0) {
9068 81 return;
9069 }
9070
9071
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 saved_path.assign(file_path);
9072 30 found_path = true;
9073
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 229 times.
259 });
9074
9075 /* Check and rename the import file name. */
9076
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
42 if (found_path) {
9077
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 fil_rename_partition_file(saved_path, extn, false, true);
9078 }
9079 #endif /* !WIN32 */
9080
9081 42 return;
9082 42 }
9083
9084 728 dberr_t fil_tablespace_iterate(dict_table_t *table, ulint n_io_buffers,
9085 Compression::Type compression_type,
9086 PageCallback &callback) {
9087 dberr_t err;
9088 pfs_os_file_t file;
9089 char *filepath;
9090 bool success;
9091
9092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 728 times.
728 ut_a(n_io_buffers > 0);
9093
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 728 times.
728 ut_ad(!srv_read_only_mode);
9094
9095
3/4
✓ Branch 0 taken 728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 726 times.
728 DBUG_EXECUTE_IF("ib_import_trigger_corruption_1", return DB_CORRUPTION;);
9096
9097 /* Make sure the data_dir_path is set. */
9098
1/2
✓ Branch 0 taken 726 times.
✗ Branch 1 not taken.
726 dd_get_and_save_data_dir_path<dd::Table>(table, nullptr, false);
9099
9100
1/2
✓ Branch 0 taken 726 times.
✗ Branch 1 not taken.
726 std::string path = dict_table_get_datadir(table);
9101
9102
2/4
✓ Branch 0 taken 726 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 726 times.
✗ Branch 3 not taken.
726 filepath = Fil_path::make(path, table->name.m_name, IBD, true);
9103
9104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 726 times.
726 if (filepath == nullptr) {
9105 return DB_OUT_OF_MEMORY;
9106 }
9107
9108 /* Adjust filename for partition file if in different letter case. */
9109
1/2
✓ Branch 0 taken 726 times.
✗ Branch 1 not taken.
726 fil_adjust_name_import(table, filepath, IBD);
9110
9111
1/2
✓ Branch 0 taken 726 times.
✗ Branch 1 not taken.
726 file = os_file_create_simple_no_error_handling(
9112 innodb_data_file_key, filepath, OS_FILE_OPEN, OS_FILE_READ_WRITE,
9113 srv_read_only_mode, &success);
9114
9115
2/14
✓ Branch 0 taken 726 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 726 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
726 DBUG_EXECUTE_IF("fil_tablespace_iterate_failure", {
9116 static bool once;
9117
9118 if (!once || ut::random_from_interval(0, 10) == 5) {
9119 once = true;
9120 success = false;
9121 os_file_close(file);
9122 }
9123 });
9124
9125
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 700 times.
726 if (!success) {
9126 /* The following call prints an error message */
9127
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 os_file_get_last_error(true);
9128
9129
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
52 ib::error(ER_IB_MSG_337) << "Trying to import a tablespace, but could not"
9130
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 " open the tablespace file "
9131
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 << filepath;
9132
9133 26 ut::free(filepath);
9134
9135 26 return DB_TABLESPACE_NOT_FOUND;
9136
9137 } else {
9138 700 err = DB_SUCCESS;
9139 }
9140
9141 /* Set File System Block Size */
9142 size_t block_size;
9143 {
9144 os_file_stat_t stat_info;
9145
9146
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 ut_d(dberr_t err =) os_file_get_status(filepath, &stat_info, false, false);
9147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
700 ut_ad(err == DB_SUCCESS);
9148
9149 700 block_size = stat_info.block_size;
9150 }
9151
9152 700 callback.set_file(filepath, file);
9153
9154
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 os_offset_t file_size = os_file_get_size(file);
9155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
700 ut_a(file_size != (os_offset_t)-1);
9156
9157 /* The block we will use for every physical page */
9158 buf_block_t *block;
9159
9160 block = reinterpret_cast<buf_block_t *>(
9161 700 ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, sizeof(*block)));
9162
9163
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 mutex_create(LATCH_ID_BUF_BLOCK_MUTEX, &block->mutex);
9164
9165 /* Allocate a page to read in the tablespace header, so that we
9166 can determine the page size and zip size (if it is compressed).
9167 We allocate an extra page in case it is a compressed table. One
9168 page is to ensure alignment. */
9169
9170 byte *page = static_cast<byte *>(
9171 700 ut::aligned_alloc(2 * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
9172
9173 700 fil_buf_block_init(block, page);
9174
9175 /* Read the first page and determine the page and zip size. */
9176
9177
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 IORequest request(IORequest::READ);
9178
9179
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 err = os_file_read_first_page(request, path.c_str(), file, page,
9180 UNIV_PAGE_SIZE);
9181
9182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
700 if (err != DB_SUCCESS) {
9183 err = DB_IO_ERROR;
9184
9185
2/4
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 700 times.
✗ Branch 3 not taken.
700 } else if ((err = callback.init(file_size, block)) == DB_SUCCESS) {
9186 700 Fil_page_iterator iter;
9187
9188 700 iter.m_file = file;
9189 700 iter.m_start = 0;
9190 700 iter.m_end = file_size;
9191 700 iter.m_filepath = filepath;
9192 700 iter.m_file_size = file_size;
9193 700 iter.m_n_io_buffers = n_io_buffers;
9194
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 iter.m_page_size = callback.get_page_size().physical();
9195 700 iter.block_size = block_size;
9196
9197 700 iter.m_compression_type = compression_type;
9198
9199 /* Check encryption is matched or not. */
9200
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 ulint space_flags = callback.get_space_flags();
9201 700 iter.m_crypt_data =
9202
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 fil_space_read_crypt_data(callback.get_page_size(), page);
9203
9204 /* read (optional) crypt data */
9205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
700 if (iter.m_crypt_data &&
9206 iter.m_crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) {
9207 ut_ad(FSP_FLAGS_GET_ENCRYPTION(space_flags));
9208 iter.m_encryption_key_id = iter.m_crypt_data->key_id;
9209
9210 Encryption::get_latest_tablespace_key(
9211 iter.m_crypt_data->key_id, iter.m_crypt_data->uuid,
9212 &iter.m_encryption_key_version, &iter.m_encryption_key);
9213 if (iter.m_encryption_key == NULL) err = DB_IO_DECRYPT_FAIL;
9214 } else {
9215 /* Set encryption info. */
9216 700 iter.m_encryption_key = table->encryption_key;
9217 700 iter.m_encryption_iv = table->encryption_iv;
9218 700 iter.m_encryption_key_version = ~0; // TODO:Robert:flipping bits so to
9219 // make this a marker that tablespace
9220 // key id used
9221 }
9222
9223 /* Check encryption is matched or not. */
9224
5/6
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 525 times.
✓ Branch 4 taken 175 times.
✓ Branch 5 taken 525 times.
700 if (err == DB_SUCCESS && FSP_FLAGS_GET_ENCRYPTION(space_flags)) {
9225
3/4
✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 155 times.
175 if (!dd_is_table_in_encrypted_tablespace(table)) {
9226
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
40 ib::error(ER_IB_MSG_338) << "Table is not in an encrypted tablespace,"
9227 " but the data file intended for import"
9228
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 " is an encrypted tablespace";
9229
9230 20 err = DB_IO_NO_ENCRYPT_TABLESPACE;
9231 } else {
9232 /* encryption_key must have been populated while reading CFP file. */
9233
3/6
✓ Branch 0 taken 155 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 155 times.
155 ut_ad(table->encryption_key != nullptr &&
9234 table->encryption_iv != nullptr);
9235
9236
1/2
✓ Branch 0 taken 155 times.
✗ Branch 1 not taken.
155 if (table->encryption_key == nullptr ||
9237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 155 times.
155 table->encryption_iv == nullptr) {
9238 err = DB_ERROR;
9239 }
9240 }
9241 }
9242
9243
2/2
✓ Branch 0 taken 680 times.
✓ Branch 1 taken 20 times.
700 if (err == DB_SUCCESS) {
9244 /* Compressed pages can't be optimised for block IO
9245 for now. We do the IMPORT page by page. */
9246
9247
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 655 times.
680 if (callback.get_page_size().is_compressed()) {
9248 25 iter.m_n_io_buffers = 1;
9249
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
25 ut_a(iter.m_page_size == callback.get_page_size().physical());
9250 }
9251
9252 /** Add an extra page for compressed page scratch
9253 area. */
9254 1360 iter.m_io_buffer = static_cast<byte *>(ut::aligned_alloc(
9255 680 (1 + iter.m_n_io_buffers) * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE));
9256
9257
1/2
✓ Branch 0 taken 660 times.
✗ Branch 1 not taken.
680 err = fil_iterate(iter, block, callback);
9258
9259 660 ut::aligned_free(iter.m_io_buffer);
9260 }
9261
9262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 680 times.
680 if (iter.m_crypt_data) {
9263 fil_space_destroy_crypt_data(&iter.m_crypt_data);
9264 if (iter.m_encryption_key != NULL) my_free(iter.m_encryption_key);
9265 }
9266 }
9267
9268
2/2
✓ Branch 0 taken 654 times.
✓ Branch 1 taken 26 times.
680 if (err == DB_SUCCESS) {
9269
2/4
✓ Branch 0 taken 654 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 654 times.
✗ Branch 3 not taken.
654 ib::info(ER_IB_MSG_339) << "Sync to disk";
9270
9271
2/4
✓ Branch 0 taken 654 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 654 times.
654 if (!os_file_flush(file)) {
9272 ib::info(ER_IB_MSG_340) << "os_file_flush() failed!";
9273 err = DB_IO_ERROR;
9274 } else {
9275
2/4
✓ Branch 0 taken 654 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 654 times.
✗ Branch 3 not taken.
654 ib::info(ER_IB_MSG_341) << "Sync to disk - done!";
9276 }
9277 }
9278
9279
1/2
✓ Branch 0 taken 680 times.
✗ Branch 1 not taken.
680 os_file_close(file);
9280
9281 680 ut::aligned_free(page);
9282 680 ut::free(filepath);
9283
9284
1/2
✓ Branch 0 taken 680 times.
✗ Branch 1 not taken.
680 mutex_free(&block->mutex);
9285
9286 680 ut::free(block);
9287
9288 680 return err;
9289 706 }
9290 #endif /* !UNIV_HOTBACKUP */
9291
9292 /** Set the tablespace table size.
9293 @param[in] page a page belonging to the tablespace */
9294 700 void PageCallback::set_page_size(const buf_frame_t *page) UNIV_NOTHROW {
9295
1/2
✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
700 m_page_size.copy_from(fsp_header_get_page_size(page));
9296 700 }
9297
9298 /** Delete the tablespace file and any related files like .cfg.
9299 This should not be called for temporary tables.
9300 @param[in] path File path of the IBD tablespace
9301 @return true on success */
9302 331 bool fil_delete_file(const char *path) {
9303 331 bool success = true;
9304
9305 /* Force a delete of any stale .ibd files that are lying around. */
9306 331 success = os_file_delete_if_exists(innodb_data_file_key, path, nullptr);
9307
9308
2/4
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 331 times.
✗ Branch 3 not taken.
331 char *cfg_filepath = Fil_path::make_cfg(path);
9309
9310
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 if (cfg_filepath != nullptr) {
9311 331 os_file_delete_if_exists(innodb_data_file_key, cfg_filepath, nullptr);
9312
9313 331 ut::free(cfg_filepath);
9314 }
9315
9316
2/4
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 331 times.
✗ Branch 3 not taken.
331 char *cfp_filepath = Fil_path::make_cfp(path);
9317
9318
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 if (cfp_filepath != nullptr) {
9319 331 os_file_delete_if_exists(innodb_data_file_key, cfp_filepath, nullptr);
9320
9321 331 ut::free(cfp_filepath);
9322 }
9323
9324 331 return success;
9325 }
9326
9327 #ifndef UNIV_HOTBACKUP
9328 30250 dberr_t fil_rename_precheck(const dict_table_t *old_table,
9329 const dict_table_t *new_table,
9330 const char *tmp_name) {
9331
1/2
✓ Branch 0 taken 30250 times.
✗ Branch 1 not taken.
30250 bool old_is_file_per_table = dict_table_is_file_per_table(old_table);
9332
1/2
✓ Branch 0 taken 30250 times.
✗ Branch 1 not taken.
30250 bool new_is_file_per_table = dict_table_is_file_per_table(new_table);
9333
9334 /* If neither table is file-per-table, there will be no renaming of files. */
9335
4/4
✓ Branch 0 taken 10709 times.
✓ Branch 1 taken 19541 times.
✓ Branch 2 taken 10592 times.
✓ Branch 3 taken 117 times.
30250 if (!old_is_file_per_table && !new_is_file_per_table) {
9336 10592 return DB_SUCCESS;
9337 }
9338
9339 37440 auto fetch_path = [](std::string &path, const dict_table_t *source_table,
9340 bool fpt) -> dberr_t {
9341 37440 char *path_ptr{};
9342
9343 /* It is possible that the file could be present in a directory outside of
9344 the data directory (possible because of innodb_directories option), so
9345 fetch the path accordingly.
9346
9347 We are only interested in fetching the right path for file-per-table
9348 tablespaces as during file_rename_tablespace_check the source table should
9349 always exist and we do the rename for only source tables which are
9350 file-per-table tablspaces. */
9351
6/6
✓ Branch 0 taken 37323 times.
✓ Branch 1 taken 117 times.
✓ Branch 2 taken 37315 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 37315 times.
✓ Branch 5 taken 125 times.
37440 if (fpt && !dict_table_is_discarded(source_table)) {
9352 37315 path_ptr = fil_space_get_first_path(source_table->space);
9353
9354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37315 times.
37315 if (path_ptr == nullptr) {
9355 return DB_TABLESPACE_NOT_FOUND;
9356 }
9357 } else {
9358
1/2
✓ Branch 0 taken 125 times.
✗ Branch 1 not taken.
125 auto dir = dict_table_get_datadir(source_table);
9359
9360 path_ptr =
9361
2/4
✓ Branch 0 taken 125 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 125 times.
✗ Branch 3 not taken.
125 Fil_path::make(dir, source_table->name.m_name, IBD, !dir.empty());
9362
9363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 125 times.
125 if (path_ptr == nullptr) {
9364 return DB_OUT_OF_MEMORY;
9365 }
9366
1/2
✓ Branch 0 taken 125 times.
✗ Branch 1 not taken.
125 }
9367
9368 37440 path.assign(path_ptr);
9369 37440 ut::free(path_ptr);
9370
9371 37440 return DB_SUCCESS;
9372 };
9373
9374 19658 std::string old_path;
9375
9376
1/2
✓ Branch 0 taken 19658 times.
✗ Branch 1 not taken.
19658 auto err = fetch_path(old_path, old_table, old_is_file_per_table);
9377
9378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19658 times.
19658 if (err != DB_SUCCESS) {
9379 return err;
9380 }
9381
9382
2/2
✓ Branch 0 taken 19541 times.
✓ Branch 1 taken 117 times.
19658 if (old_is_file_per_table) {
9383 std::string tmp_path =
9384
3/6
✓ Branch 0 taken 19541 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19541 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19541 times.
✗ Branch 5 not taken.
39082 Fil_path::make_new_path(old_path.c_str(), tmp_name, IBD);
9385
9386 /* Temp filepath must not exist. */
9387
1/2
✓ Branch 0 taken 19541 times.
✗ Branch 1 not taken.
19541 err = fil_rename_tablespace_check(old_table->space, old_path.c_str(),
9388 tmp_path.c_str(),
9389 19541 dict_table_is_discarded(old_table));
9390
9391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19541 times.
19541 if (err != DB_SUCCESS) {
9392 return err;
9393 }
9394
1/2
✓ Branch 0 taken 19541 times.
✗ Branch 1 not taken.
19541 }
9395
9396
2/2
✓ Branch 0 taken 17782 times.
✓ Branch 1 taken 1876 times.
19658 if (new_is_file_per_table) {
9397 17782 std::string new_path;
9398
9399
1/2
✓ Branch 0 taken 17782 times.
✗ Branch 1 not taken.
17782 err = fetch_path(new_path, new_table, new_is_file_per_table);
9400
9401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17782 times.
17782 if (err != DB_SUCCESS) {
9402 return err;
9403 }
9404
9405 /* Destination filepath must not exist unless this ALTER TABLE starts and
9406 ends with a file_per-table tablespace. */
9407
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 17665 times.
17782 if (!old_is_file_per_table) {
9408
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 err = fil_rename_tablespace_check(new_table->space, new_path.c_str(),
9409 old_path.c_str(),
9410 117 dict_table_is_discarded(new_table));
9411 }
9412
1/2
✓ Branch 0 taken 17782 times.
✗ Branch 1 not taken.
17782 }
9413
9414 19658 return err;
9415 19658 }
9416 #endif /* !UNIV_HOTBACKUP */
9417
9418 /** Note that the file system where the file resides doesn't support PUNCH HOLE.
9419 Called from AIO handlers when IO returns DB_IO_NO_PUNCH_HOLE
9420 @param[in,out] file file to set */
9421 1475 void fil_no_punch_hole(fil_node_t *file) { file->punch_hole = false; }
9422
9423 478979 dberr_t fil_set_compression(space_id_t space_id, const char *algorithm) {
9424 dberr_t err;
9425 478979 Compression compression;
9426
9427
3/4
✓ Branch 0 taken 674 times.
✓ Branch 1 taken 478308 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 674 times.
478982 if (algorithm == nullptr || strlen(algorithm) == 0) {
9428 #ifndef UNIV_DEBUG
9429 compression.m_type = Compression::NONE;
9430 #else /* UNIV_DEBUG */
9431 /* This is a Debug tool for setting compression on all
9432 compressible tables not otherwise specified. */
9433
1/2
✓ Branch 0 taken 478308 times.
✗ Branch 1 not taken.
478308 switch (srv_debug_compress) {
9434 478308 case Compression::LZ4:
9435 case Compression::ZLIB:
9436 case Compression::NONE:
9437
9438 478308 compression.m_type = static_cast<Compression::Type>(srv_debug_compress);
9439 478308 break;
9440
9441 default:
9442 compression.m_type = Compression::NONE;
9443 }
9444
9445 #endif /* UNIV_DEBUG */
9446
9447 478308 err = DB_SUCCESS;
9448
9449 } else {
9450
1/2
✓ Branch 0 taken 674 times.
✗ Branch 1 not taken.
674 err = Compression::check(algorithm, &compression);
9451 }
9452
9453
1/2
✓ Branch 0 taken 478982 times.
✗ Branch 1 not taken.
478982 fil_space_t *space = fil_space_get(space_id);
9454
9455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478982 times.
478982 if (space == nullptr) {
9456 return DB_NOT_FOUND;
9457 }
9458
9459
1/2
✓ Branch 0 taken 478982 times.
✗ Branch 1 not taken.
478982 const page_size_t page_size(space->flags);
9460
9461
1/2
✓ Branch 0 taken 478982 times.
✗ Branch 1 not taken.
478982 if (!fsp_is_file_per_table(space_id, space->flags) ||
9462
5/10
✓ Branch 0 taken 478982 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478981 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 478981 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 478981 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 478981 times.
478982 fsp_is_system_temporary(space_id) || page_size.is_compressed()) {
9463 return DB_IO_NO_PUNCH_HOLE_TABLESPACE;
9464 }
9465
9466 478981 space->compression_type = compression.m_type;
9467
9468
2/2
✓ Branch 0 taken 493 times.
✓ Branch 1 taken 478488 times.
478981 if (space->compression_type != Compression::NONE) {
9469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 493 times.
493 if (!space->files.front().punch_hole) {
9470 return DB_IO_NO_PUNCH_HOLE_FS;
9471 }
9472 }
9473
9474 478981 return err;
9475 }
9476
9477 /** Get the compression algorithm for a tablespace.
9478 @param[in] space_id Space ID to check
9479 @return the compression algorithm */
9480 701 Compression::Type fil_get_compression(space_id_t space_id) {
9481 701 fil_space_t *space = fil_space_get(space_id);
9482
9483
1/2
✓ Branch 0 taken 701 times.
✗ Branch 1 not taken.
701 return space == nullptr ? Compression::NONE : space->compression_type;
9484 }
9485
9486 /** Set the autoextend_size attribute for the tablespace
9487 @param[in] space_id Space ID of tablespace for which to set
9488 @param[in] autoextend_size Value of autoextend_size attribute
9489 @return DB_SUCCESS or error code */
9490 357762 dberr_t fil_set_autoextend_size(space_id_t space_id, uint64_t autoextend_size) {
9491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357762 times.
357762 ut_ad(space_id != TRX_SYS_SPACE);
9492
9493 357762 fil_space_t *space = fil_space_acquire(space_id);
9494
9495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 357762 times.
357762 if (space == nullptr) {
9496 return DB_NOT_FOUND;
9497 }
9498
9499 357762 rw_lock_x_lock(&space->latch, UT_LOCATION_HERE);
9500
9501 357762 space->autoextend_size_in_bytes = autoextend_size;
9502
9503 357762 rw_lock_x_unlock(&space->latch);
9504
9505 357762 fil_space_release(space);
9506
9507 357762 return DB_SUCCESS;
9508 }
9509
9510 /** Set the encryption type for the tablespace
9511 @param[in] space_id Space ID of tablespace for which to set
9512 @param[in] algorithm Encryption algorithm
9513 @param[in] key Encryption key
9514 @param[in] iv Encryption iv
9515 @param[in] acquire_mutex if true acquire fil_sys mutex, else false
9516 @return DB_SUCCESS or error code */
9517 7718 dberr_t fil_set_encryption(space_id_t space_id, Encryption::Type algorithm,
9518 byte *key, byte *iv, bool acquire_mutex) {
9519 7718 auto shard = fil_system->shard_by_id(space_id);
9520
9521
1/2
✓ Branch 0 taken 7718 times.
✗ Branch 1 not taken.
7718 if (acquire_mutex) shard->mutex_acquire();
9522
9523 7718 fil_space_t *space = shard->get_space_by_id(space_id);
9524
9525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7718 times.
7718 if (space == nullptr) {
9526 if (acquire_mutex) {
9527 shard->mutex_release();
9528 }
9529 return DB_NOT_FOUND;
9530 }
9531
9532 7718 Encryption::set_or_generate(algorithm, key, iv, space->m_encryption_metadata);
9533
9534
2/2
✓ Branch 0 taken 7702 times.
✓ Branch 1 taken 16 times.
7718 if (space->crypt_data == nullptr) fsp_flags_set_encryption(space->flags);
9535
9536
1/2
✓ Branch 0 taken 7718 times.
✗ Branch 1 not taken.
7718 if (acquire_mutex) {
9537 7718 shard->mutex_release();
9538 }
9539
9540 7718 return DB_SUCCESS;
9541 }
9542
9543 /** Enable encryption of temporary tablespace
9544 @param[in,out] space tablespace object
9545 @return DB_SUCCESS on success, DB_ERROR on failure */
9546 161 dberr_t fil_temp_update_encryption(fil_space_t *space) {
9547 /* Make sure the keyring is loaded. */
9548
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 158 times.
161 if (!Encryption::check_keyring()) {
9549
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 ib::error() << "Can't set temporary tablespace"
9550
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 << " to be encrypted because"
9551
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 << " keyring plugin is not"
9552
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 << " available.";
9553 3 return (DB_ERROR);
9554 }
9555
9556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
158 if (!fsp_enable_encryption(space)) {
9557 ib::error() << "Can't set temporary tablespace"
9558 << " to be encrypted.";
9559 return (DB_ERROR);
9560 }
9561
9562 const dberr_t err =
9563 158 fil_set_encryption(space->id, Encryption::AES, nullptr, nullptr);
9564
9565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
158 ut_ad(err == DB_SUCCESS);
9566
9567 158 return (err);
9568 }
9569
9570 /** Reset the encryption type for the tablespace
9571 @param[in] space_id Space ID of tablespace for which to set
9572 @return DB_SUCCESS or error code */
9573 236 dberr_t fil_reset_encryption(space_id_t space_id) {
9574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 ut_ad(space_id != TRX_SYS_SPACE);
9575
9576 236 auto shard = fil_system->shard_by_id(space_id);
9577
9578 236 shard->mutex_acquire();
9579
9580 236 fil_space_t *space = shard->get_space_by_id(space_id);
9581
9582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (space == nullptr) {
9583 shard->mutex_release();
9584 return DB_NOT_FOUND;
9585 }
9586
9587 236 space->m_encryption_metadata = {};
9588
9589 236 shard->mutex_release();
9590
9591 236 return DB_SUCCESS;
9592 }
9593
9594 #ifndef UNIV_HOTBACKUP
9595 469203 bool Fil_shard::needs_encryption_rotate(fil_space_t *space) {
9596 /* We only rotate if encryption is already set. */
9597
2/2
✓ Branch 0 taken 351762 times.
✓ Branch 1 taken 117441 times.
469203 if (!space->can_encrypt()) {
9598 351762 return false;
9599 }
9600
9601 /* Deleted spaces do not need rotation. Their pages are being
9602 deleted from the buffer pool. */
9603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117441 times.
117441 if (space->is_deleted()) {
9604 return false;
9605 }
9606
9607 /* Skip unencypted tablespaces. */
9608
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 117394 times.
117441 if (fsp_is_system_or_temp_tablespace(space->id)) {
9609 47 return false;
9610 }
9611
9612
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 117390 times.
117394 DBUG_EXECUTE_IF(
9613 "ib_encryption_rotate_skip",
9614 ib::info(ER_IB_MSG_INJECT_FAILURE, "ib_encryption_rotate_skip");
9615 return false;);
9616
9617 117390 return true;
9618 }
9619
9620 1025276 size_t Fil_shard::encryption_rotate(size_t *rotate_count) {
9621 /* If there are no tablespaces to rotate, return true. */
9622 1025276 size_t fail_count = 0;
9623 byte encrypt_info[Encryption::INFO_SIZE];
9624 using Spaces_to_rotate = std::vector<fil_space_t *>;
9625 1025276 Spaces_to_rotate spaces2rotate;
9626
9627 /* Use the shard mutex to collect a list of the spaces to rotate. */
9628
1/2
✓ Branch 0 taken 1025276 times.
✗ Branch 1 not taken.
1025276 mutex_acquire();
9629
9630
2/2
✓ Branch 0 taken 469203 times.
✓ Branch 1 taken 1025276 times.
1494479 for (auto &elem : m_spaces) {
9631 469203 auto space = elem.second;
9632
9633
3/4
✓ Branch 0 taken 469203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 351813 times.
✓ Branch 3 taken 117390 times.
469203 if (!needs_encryption_rotate(space)) {
9634 351813 continue;
9635 }
9636
9637 /* Skip the temporary tablespace when it's in default key status,
9638 since it's the first server startup after bootstrap, and the
9639 server uuid is not ready yet. */
9640
3/6
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 117390 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 117390 times.
117390 if (fsp_is_system_temporary(space->id) &&
9641 Encryption::get_master_key_id() == Encryption::DEFAULT_MASTER_KEY_ID)
9642 continue;
9643
9644
1/2
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
117390 spaces2rotate.push_back(space);
9645 }
9646
9647
1/2
✓ Branch 0 taken 1025276 times.
✗ Branch 1 not taken.
1025276 mutex_release();
9648
9649 /* We can now be assured that each fil_space_t collected above will not be
9650 deleted below (outside the shard mutex protection) because:
9651 1. The caller, Rotate_innodb_master_key::execute(), holds an exclusive
9652 backup lock which blocks any other concurrent DDL or MDL on this space.
9653 2. Only a thread with an MDL on the space name can mark a fil_space_t as
9654 deleted or actually delete it. This includes background threads like
9655 the purge thread doing undo truncation as well as any client DDL.
9656 3. We assured above using the shard mutex that the space is not deleted. */
9657
9658
2/2
✓ Branch 0 taken 117390 times.
✓ Branch 1 taken 1025276 times.
1142666 for (auto &space : spaces2rotate) {
9659 /* Rotate this encrypted tablespace. */
9660
1/2
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
117390 mtr_t mtr;
9661
1/2
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
117390 mtr_start(&mtr);
9662 117390 memset(encrypt_info, 0, Encryption::INFO_SIZE);
9663
1/2
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
117390 bool rotate_ok = fsp_header_rotate_encryption(space, encrypt_info, &mtr);
9664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117390 times.
117390 ut_ad(rotate_ok);
9665
1/2
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
117390 mtr_commit(&mtr);
9666
9667
1/2
✓ Branch 0 taken 117390 times.
✗ Branch 1 not taken.
117390 if (rotate_ok) {
9668 117390 ++(*rotate_count);
9669 } else {
9670 ++fail_count;
9671 }
9672 117390 }
9673
9674 /* This crash forces encryption rotate to complete at startup. */
9675
5/8
✓ Branch 0 taken 1025276 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 1025236 times.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✗ Branch 7 not taken.
1025276 DBUG_EXECUTE_IF(
9676 "ib_encryption_rotate_crash",
9677 ib::info(ER_IB_MSG_INJECT_FAILURE, "ib_encryption_rotate_crash");
9678 DBUG_SUICIDE(););
9679
9680 1025236 return fail_count;
9681 1025236 }
9682
9683 15117 size_t Fil_system::encryption_rotate() {
9684 15117 size_t fail_count = 0;
9685 15117 size_t rotate_count = 0;
9686
9687
2/2
✓ Branch 0 taken 1025276 times.
✓ Branch 1 taken 15077 times.
1040353 for (auto shard : m_shards) {
9688
1/2
✓ Branch 0 taken 1025236 times.
✗ Branch 1 not taken.
1025276 fail_count += shard->encryption_rotate(&rotate_count);
9689 }
9690
9691
2/2
✓ Branch 0 taken 3636 times.
✓ Branch 1 taken 11441 times.
15077 if (rotate_count > 0) {
9692
1/2
✓ Branch 0 taken 3636 times.
✗ Branch 1 not taken.
3636 ib::info(ER_IB_MSG_MASTER_KEY_ROTATED, static_cast<int>(rotate_count));
9693 }
9694
9695 15077 return fail_count;
9696 }
9697
9698 11531 void Fil_system::encryption_reencrypt(
9699 std::vector<space_id_t> &space_id_vector) {
9700 /* If there are no tablespaces to reencrypt, return true. */
9701
1/2
✓ Branch 0 taken 11531 times.
✗ Branch 1 not taken.
11531 if (space_id_vector.empty()) {
9702 11531 return;
9703 }
9704
9705 size_t fail_count = 0;
9706 size_t rotate_count = 0;
9707 byte encrypt_info[Encryption::INFO_SIZE];
9708
9709 /* This operation is done either post recovery or when the first time
9710 tablespace is loaded. */
9711
9712 for (auto &space_id : space_id_vector) {
9713 fil_space_t *space = fil_space_get(space_id);
9714 ut_ad(space != nullptr);
9715 ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags));
9716
9717 /* Rotate this encrypted tablespace. */
9718 mtr_t mtr;
9719 mtr_start(&mtr);
9720 memset(encrypt_info, 0, Encryption::INFO_SIZE);
9721 bool rotate_ok = fsp_header_rotate_encryption(space, encrypt_info, &mtr);
9722 ut_ad(rotate_ok);
9723 mtr_commit(&mtr);
9724
9725 if (rotate_ok) {
9726 ++rotate_count;
9727 if (fsp_is_ibd_tablespace(space_id)) {
9728 if (fsp_is_file_per_table(space_id, space->flags)) {
9729 ib::info(ER_IB_MSG_REENCRYPTED_TABLESPACE_KEY, space->name);
9730 } else {
9731 ib::info(ER_IB_MSG_REENCRYPTED_GENERAL_TABLESPACE_KEY, space->name);
9732 }
9733 }
9734 } else {
9735 ++fail_count;
9736 }
9737 }
9738
9739 /* The operation should finish successfully for all tablespaces */
9740 ut_a(fail_count == 0);
9741 }
9742
9743 15117 size_t fil_encryption_rotate() { return (fil_system->encryption_rotate()); }
9744
9745 11531 void fil_encryption_reencrypt(std::vector<space_id_t> &sid_vector) {
9746 11531 fil_system->encryption_reencrypt(sid_vector);
9747 11531 }
9748
9749 #endif /* !UNIV_HOTBACKUP */
9750
9751 /** Constructor
9752 @param[in] path pathname (may also include the file basename)
9753 @param[in] normalize_path If false, it's the callers responsibility to
9754 ensure that the path is normalized. */
9755 715774 Fil_path::Fil_path(const std::string &path, bool normalize_path)
9756 715774 : m_path(path) {
9757
2/2
✓ Branch 0 taken 25824 times.
✓ Branch 1 taken 689950 times.
715774 if (normalize_path) {
9758 25824 normalize(m_path);
9759 }
9760
9761
1/2
✓ Branch 0 taken 715774 times.
✗ Branch 1 not taken.
715774 m_abs_path = get_real_path(m_path, false);
9762 715774 }
9763
9764 /** Constructor
9765 @param[in] path Path, not necessarily NUL terminated
9766 @param[in] normalize_path If false, it's the callers responsibility to
9767 ensure that the path is normalized. */
9768
1/2
✓ Branch 0 taken 23969 times.
✗ Branch 1 not taken.
23969 Fil_path::Fil_path(const char *path, bool normalize_path) : m_path(path) {
9769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23969 times.
23969 if (normalize_path) {
9770 normalize(m_path);
9771 }
9772
9773
1/2
✓ Branch 0 taken 23969 times.
✗ Branch 1 not taken.
23969 m_abs_path = get_real_path(m_path, false);
9774 23969 }
9775
9776 /** Constructor
9777 @param[in] path Path, not necessarily NUL terminated
9778 @param[in] len Length of path
9779 @param[in] normalize_path If false, it's the callers responsibility to
9780 ensure that the path is normalized. */
9781 83264 Fil_path::Fil_path(const char *path, size_t len, bool normalize_path)
9782
1/2
✓ Branch 0 taken 83264 times.
✗ Branch 1 not taken.
83264 : m_path(path, len) {
9783
1/2
✓ Branch 0 taken 83264 times.
✗ Branch 1 not taken.
83264 if (normalize_path) {
9784 83264 normalize(m_path);
9785 }
9786
9787
1/2
✓ Branch 0 taken 83264 times.
✗ Branch 1 not taken.
83264 m_abs_path = get_real_path(m_path, false);
9788 83264 }
9789
9790 /** Default constructor. */
9791 24330 Fil_path::Fil_path() : m_path(), m_abs_path() { /* No op */
9792 24330 }
9793
9794 43994 bool Fil_path::is_same_as(const Fil_path &other) const {
9795
3/6
✓ Branch 0 taken 43994 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43994 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 43994 times.
43994 if (path().empty() || other.path().empty()) {
9796 return false;
9797 }
9798
9799
1/2
✓ Branch 0 taken 43994 times.
✗ Branch 1 not taken.
43994 std::string first = abs_path();
9800
1/2
✓ Branch 0 taken 43994 times.
✗ Branch 1 not taken.
43994 trim_separator(first);
9801
9802
1/2
✓ Branch 0 taken 43994 times.
✗ Branch 1 not taken.
43994 std::string second = other.abs_path();
9803
1/2
✓ Branch 0 taken 43994 times.
✗ Branch 1 not taken.
43994 trim_separator(second);
9804
9805 43994 return (first == second);
9806 43994 }
9807
9808 11921 bool Fil_path::is_same_as(const std::string &other) const {
9809
3/6
✓ Branch 0 taken 11921 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11921 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 11921 times.
11921 if (path().empty() || other.empty()) {
9810 return false;
9811 }
9812
9813
1/2
✓ Branch 0 taken 11921 times.
✗ Branch 1 not taken.
11921 Fil_path other_path(other);
9814
9815
1/2
✓ Branch 0 taken 11921 times.
✗ Branch 1 not taken.
11921 return is_same_as(other_path);
9816 11921 }
9817
9818 369 std::pair<std::string, std::string> Fil_path::split(const std::string &path) {
9819 369 const auto n = path.rfind(OS_PATH_SEPARATOR);
9820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
369 ut_ad(n != std::string::npos);
9821
1/2
✓ Branch 0 taken 369 times.
✗ Branch 1 not taken.
369 return {path.substr(0, n), path.substr(n)};
9822 }
9823
9824 102114 bool Fil_path::is_ancestor(const Fil_path &other) const {
9825
3/6
✓ Branch 0 taken 102114 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102114 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 102114 times.
102114 if (path().empty() || other.path().empty()) {
9826 return false;
9827 }
9828
9829
1/2
✓ Branch 0 taken 102114 times.
✗ Branch 1 not taken.
102114 std::string ancestor = abs_path();
9830
1/2
✓ Branch 0 taken 102114 times.
✗ Branch 1 not taken.
102114 std::string descendant = other.abs_path();
9831
9832 /* We do not know if the descendant is a dir or a file.
9833 But the ancestor in this routine is always a directory.
9834 If it does not yet exist, it may not have a trailing separator.
9835 If there is no trailing separator, add it. */
9836
1/2
✓ Branch 0 taken 102114 times.
✗ Branch 1 not taken.
102114 append_separator(ancestor);
9837
9838
2/2
✓ Branch 0 taken 26702 times.
✓ Branch 1 taken 75412 times.
102114 if (descendant.length() <= ancestor.length()) {
9839 26702 return false;
9840 }
9841
9842
1/2
✓ Branch 0 taken 75412 times.
✗ Branch 1 not taken.
75412 return std::equal(ancestor.begin(), ancestor.end(), descendant.begin());
9843 102114 }
9844
9845 12039 bool Fil_path::is_ancestor(const std::string &other) const {
9846
3/6
✓ Branch 0 taken 12039 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12039 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12039 times.
12039 if (path().empty() || other.empty()) {
9847 return false;
9848 }
9849
9850
1/2
✓ Branch 0 taken 12039 times.
✗ Branch 1 not taken.
12039 Fil_path descendant(other);
9851
9852
1/2
✓ Branch 0 taken 12039 times.
✗ Branch 1 not taken.
12039 return is_ancestor(descendant);
9853 12039 }
9854
9855 3151564 bool Fil_path::is_hidden(std::string path) {
9856
1/2
✓ Branch 0 taken 3151564 times.
✗ Branch 1 not taken.
3151564 std::string basename(path);
9857
1/2
✓ Branch 0 taken 3198664 times.
✗ Branch 1 not taken.
3198664 while (!basename.empty()) {
9858 3198664 char c = basename.back();
9859
5/6
✓ Branch 0 taken 3151564 times.
✓ Branch 1 taken 47100 times.
✓ Branch 2 taken 3151564 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3151564 times.
✓ Branch 5 taken 47100 times.
3198664 if (!(Fil_path::is_separator(c) || c == '*')) {
9860 3151564 break;
9861 }
9862
1/2
✓ Branch 0 taken 47100 times.
✗ Branch 1 not taken.
47100 basename.resize(basename.size() - 1);
9863 }
9864 3151564 auto sep = basename.find_last_of(SEPARATOR);
9865
9866
5/6
✓ Branch 0 taken 3151400 times.
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 3151400 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1590 times.
✓ Branch 5 taken 3149810 times.
6303128 return (sep != std::string::npos && basename[sep + 1] == '.');
9867 3151564 }
9868
9869 #ifdef _WIN32
9870 bool Fil_path::is_hidden(WIN32_FIND_DATA &dirent) {
9871 if (dirent.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
9872 dirent.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
9873 return true;
9874 }
9875
9876 return false;
9877 }
9878 #endif /* WIN32 */
9879
9880 /** @return true if the path exists and is a file . */
9881 4314275 os_file_type_t Fil_path::get_file_type(const std::string &path) {
9882 os_file_type_t type;
9883
9884
1/2
✓ Branch 0 taken 4314275 times.
✗ Branch 1 not taken.
4314275 os_file_status(path.c_str(), nullptr, &type);
9885
9886 4314275 return type;
9887 }
9888
9889 /** Return a string to display the file type of a path.
9890 @param[in] path path name
9891 @return true if the path exists and is a file . */
9892 const char *Fil_path::get_file_type_string(const std::string &path) {
9893 return get_file_type_string(Fil_path::get_file_type(path));
9894 }
9895
9896 /** Return a string to display the file type of a path.
9897 @param[in] type OS file type
9898 @return true if the path exists and is a file . */
9899 const char *Fil_path::get_file_type_string(os_file_type_t type) {
9900 switch (type) {
9901 case OS_FILE_TYPE_FILE:
9902 return "file";
9903 case OS_FILE_TYPE_LINK:
9904 return "symbolic link";
9905 case OS_FILE_TYPE_DIR:
9906 return "directory";
9907 case OS_FILE_TYPE_BLOCK:
9908 return "block device";
9909 case OS_FILE_TYPE_NAME_TOO_LONG:
9910 return "name too long";
9911 case OS_FILE_PERMISSION_ERROR:
9912 return "permission error";
9913 case OS_FILE_TYPE_MISSING:
9914 return "missing";
9915 case OS_FILE_TYPE_UNKNOWN:
9916 case OS_FILE_TYPE_FAILED:
9917 break;
9918 }
9919 return "unknown";
9920 }
9921
9922 /** @return true if the path exists and is a file . */
9923 bool Fil_path::is_file_and_exists() const {
9924 return (get_file_type(abs_path()) == OS_FILE_TYPE_FILE);
9925 }
9926
9927 /** @return true if the path exists and is a directory. */
9928 1404 bool Fil_path::is_directory_and_exists() const {
9929
1/2
✓ Branch 0 taken 1404 times.
✗ Branch 1 not taken.
1404 return (get_file_type(abs_path()) == OS_FILE_TYPE_DIR);
9930 }
9931
9932 /** This validation is only for ':'.
9933 @return true if the path is valid. */
9934 1350 bool Fil_path::is_valid() const {
9935
1/2
✓ Branch 0 taken 1350 times.
✗ Branch 1 not taken.
1350 auto count = std::count(m_path.begin(), m_path.end(), ':');
9936
9937
2/2
✓ Branch 0 taken 1348 times.
✓ Branch 1 taken 2 times.
1350 if (count == 0) {
9938 1348 return true;
9939 }
9940
9941 #ifdef _WIN32
9942 /* Do not allow names like "C:name.ibd" because it
9943 specifies the "C:" drive but allows a relative location.
9944 It should be like "c:\". If a single colon is used it
9945 must be the second byte and the third byte must be a
9946 separator. */
9947
9948 /* 8 == strlen("c:\a,ibd") */
9949 if (count == 1 && m_path.length() >= 8 && isalpha(m_path.at(0)) &&
9950 m_path.at(1) == ':' && (m_path.at(2) == '\\' || m_path.at(2) == '/')) {
9951 return true;
9952 }
9953 #endif /* _WIN32 */
9954
9955 2 return false;
9956 }
9957
9958 1704 bool Fil_path::is_circular() const {
9959 size_t first;
9960
9961 /* Find the first named directory. It is OK for a path to
9962 start with "../../../dir". */
9963
6/6
✓ Branch 0 taken 2117 times.
✓ Branch 1 taken 431 times.
✓ Branch 2 taken 413 times.
✓ Branch 3 taken 1704 times.
✓ Branch 4 taken 844 times.
✓ Branch 5 taken 1704 times.
2548 for (first = 0; m_path[first] == OS_SEPARATOR || m_path[first] == '.';
9964 ++first)
9965 ;
9966
9967 1704 size_t back_up = m_path.find(SLASH_DOT_DOT_SLASH, first);
9968
2/2
✓ Branch 0 taken 1695 times.
✓ Branch 1 taken 9 times.
1704 if (back_up == std::string::npos) {
9969 1695 return false;
9970 }
9971
9972 #ifndef _WIN32
9973 /* If the path contains a symlink before the /../ and the platform
9974 is not Windows, then '/../' does not go bback through the symlink,
9975 so it is not circular. It refers to the parent of the symlinked
9976 location and we must allow it. On Windows, it backs up to the directory
9977 where the symlink starts, which is a circular reference. */
9978
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 std::string up_path = m_path.substr(0, back_up);
9979
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (my_is_symlink(up_path.c_str(), nullptr)) {
9980 return false;
9981 }
9982 #endif /* _WIN32 */
9983
9984 9 return true;
9985 9 }
9986
9987 /** Sets the flags of the tablespace. The tablespace must be locked
9988 in MDL_EXCLUSIVE MODE.
9989 @param[in] space tablespace in-memory struct
9990 @param[in] flags tablespace flags */
9991 204195 void fil_space_set_flags(fil_space_t *space, uint32_t flags) {
9992
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204195 times.
204195 ut_ad(fsp_flags_is_valid(flags));
9993
9994 204195 rw_lock_x_lock(&space->latch, UT_LOCATION_HERE);
9995
9996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204195 times.
204195 ut_a(flags < std::numeric_limits<uint32_t>::max());
9997 204195 space->flags = (uint32_t)flags;
9998
9999 204195 rw_lock_x_unlock(&space->latch);
10000 204195 }
10001
10002 /* Unit Tests */
10003 #ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH
10004 #define MF Fil_path::make
10005 #define DISPLAY ib::info(ER_IB_MSG_342) << path
10006 void test_make_filepath() {
10007 char *path;
10008 const char *long_path =
10009 "this/is/a/very/long/path/including/a/very/"
10010 "looooooooooooooooooooooooooooooooooooooooooooooooo"
10011 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10012 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10013 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10014 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10015 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10016 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10017 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10018 "oooooooooooooooooooooooooooooooooooooooooooooooooo"
10019 "oooooooooooooooooooooooooooooooooooooooooooooooong"
10020 "/folder/name";
10021 path = MF("/this/is/a/path/with/a/filename", nullptr, IBD, false);
10022 DISPLAY;
10023 path = MF("/this/is/a/path/with/a/filename", nullptr, ISL, false);
10024 DISPLAY;
10025 path = MF("/this/is/a/path/with/a/filename", nullptr, CFG, false);
10026 DISPLAY;
10027 path = MF("/this/is/a/path/with/a/filename", nullptr, CFP, false);
10028 DISPLAY;
10029 path = MF("/this/is/a/path/with/a/filename.ibd", nullptr, IBD, false);
10030 DISPLAY;
10031 path = MF("/this/is/a/path/with/a/filename.ibd", nullptr, IBD, false);
10032 DISPLAY;
10033 path = MF("/this/is/a/path/with/a/filename.dat", nullptr, IBD, false);
10034 DISPLAY;
10035 path = MF(nullptr, "tablespacename", NO_EXT, false);
10036 DISPLAY;
10037 path = MF(nullptr, "tablespacename", IBD, false);
10038 DISPLAY;
10039 path = MF(nullptr, "dbname/tablespacename", NO_EXT, false);
10040 DISPLAY;
10041 path = MF(nullptr, "dbname/tablespacename", IBD, false);
10042 DISPLAY;
10043 path = MF(nullptr, "dbname/tablespacename", ISL, false);
10044 DISPLAY;
10045 path = MF(nullptr, "dbname/tablespacename", CFG, false);
10046 DISPLAY;
10047 path = MF(nullptr, "dbname/tablespacename", CFP, false);
10048 DISPLAY;
10049 path = MF(nullptr, "dbname\\tablespacename", NO_EXT, false);
10050 DISPLAY;
10051 path = MF(nullptr, "dbname\\tablespacename", IBD, false);
10052 DISPLAY;
10053 path = MF("/this/is/a/path", "dbname/tablespacename", IBD, false);
10054 DISPLAY;
10055 path = MF("/this/is/a/path", "dbname/tablespacename", IBD, true);
10056 DISPLAY;
10057 path = MF("./this/is/a/path", "dbname/tablespacename.ibd", IBD, true);
10058 DISPLAY;
10059 path = MF("this\\is\\a\\path", "dbname/tablespacename", IBD, true);
10060 DISPLAY;
10061 path = MF("/this/is/a/path", "dbname\\tablespacename", IBD, true);
10062 DISPLAY;
10063 path = MF(long_path, nullptr, IBD, false);
10064 DISPLAY;
10065 path = MF(long_path, "tablespacename", IBD, false);
10066 DISPLAY;
10067 path = MF(long_path, "tablespacename", IBD, true);
10068 DISPLAY;
10069 }
10070 #endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
10071
10072 /** Release the reserved free extents.
10073 @param[in] n_reserved number of reserved extents */
10074 void fil_space_t::release_free_extents(ulint n_reserved) {
10075 #ifndef UNIV_HOTBACKUP
10076 ut_ad(rw_lock_own(&latch, RW_LOCK_X));
10077 #endif /* !UNIV_HOTBACKUP */
10078
10079 ut_a(n_reserved < std::numeric_limits<uint32_t>::max());
10080 ut_a(n_reserved_extents >= n_reserved);
10081
10082 n_reserved_extents -= (uint32_t)n_reserved;
10083 }
10084
10085 #ifndef UNIV_HOTBACKUP
10086
10087 #ifdef UNIV_DEBUG
10088
10089 /** Print the extent descriptor pages of this tablespace into
10090 the given file.
10091 @param[in] filename the output file name. */
10092 148 void fil_space_t::print_xdes_pages(const char *filename) const {
10093
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 std::ofstream out(filename);
10094
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 print_xdes_pages(out);
10095 148 }
10096
10097 /** Print the extent descriptor pages of this tablespace into
10098 the given output stream.
10099 @param[in] out the output stream.
10100 @return the output stream. */
10101 148 std::ostream &fil_space_t::print_xdes_pages(std::ostream &out) const {
10102
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 mtr_t mtr;
10103
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 const page_size_t page_size(flags);
10104
10105
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 mtr_start(&mtr);
10106
10107
1/2
✓ Branch 0 taken 298 times.
✗ Branch 1 not taken.
298 for (page_no_t i = 0; i < 100; ++i) {
10108 298 page_no_t xdes_page_no = i * UNIV_PAGE_SIZE;
10109
10110
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 151 times.
298 if (xdes_page_no >= size) {
10111 147 break;
10112 }
10113
10114 buf_block_t *xdes_block =
10115
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 buf_page_get(page_id_t(id, xdes_page_no), page_size, RW_S_LATCH,
10116 UT_LOCATION_HERE, &mtr);
10117
10118
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 page_t *page = buf_block_get_frame(xdes_block);
10119
10120
1/2
✓ Branch 0 taken 151 times.
✗ Branch 1 not taken.
151 ulint page_type = fil_page_get_type(page);
10121
10122
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
151 switch (page_type) {
10123 1 case FIL_PAGE_TYPE_ALLOCATED:
10124
10125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 ut_ad(xdes_page_no >= free_limit);
10126
10127
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mtr_commit(&mtr);
10128 1 return out;
10129
10130 150 case FIL_PAGE_TYPE_FSP_HDR:
10131 case FIL_PAGE_TYPE_XDES:
10132 150 break;
10133 default:
10134 ut_error;
10135 }
10136
10137
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 xdes_page_print(out, page, xdes_page_no, &mtr);
10138 }
10139
10140
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
147 mtr_commit(&mtr);
10141 147 return out;
10142 148 }
10143 #endif /* UNIV_DEBUG */
10144
10145 /** Initialize the table space encryption
10146 @param[in,out] space Tablespace instance */
10147 311 static void fil_tablespace_encryption_init(const fil_space_t *space) {
10148
2/2
✓ Branch 0 taken 439 times.
✓ Branch 1 taken 311 times.
750 for (auto &key : *recv_sys->keys) {
10149
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 167 times.
439 if (key.space_id != space->id) {
10150 272 continue;
10151 }
10152
10153 167 dberr_t err = DB_SUCCESS;
10154
10155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 ut_ad(!fsp_is_system_tablespace(space->id));
10156
10157
3/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 46 times.
167 if (fsp_is_file_per_table(space->id, space->flags)) {
10158 /* For file-per-table tablespace, which is not INPLACE algorithm, copy
10159 what is found on REDO Log. */
10160
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv);
10161 } else {
10162 /* Here we try to populate space tablespace_key which is read during
10163 REDO scan.
10164
10165 Consider following scenario:
10166 1. Alter tablespce .. encrypt=y (KEY1)
10167 2. Alter tablespce .. encrypt=n
10168 3. Alter tablespce .. encrypt=y (KEY2)
10169
10170 Lets say there is a crash after (3) is finished successfully. Let's say
10171 we scanned till REDO of (1) but couldn't reach to REDO of (3).
10172
10173 During recovery:
10174 ----------------
10175 Case 1:
10176 - Before crash, pages of tablespace were encrypted with KEY2 and flushed.
10177 - In recovery, on REDO we've got tablespace key as KEY1.
10178 - Note, during tablespce load, KEY2 would have been found on page 0 and
10179 thus loaded already in file_space_t.
10180 - If we overwrite this space key (KEY2) with the one we got from REDO log
10181 scan (KEY1), then when we try to read a page from Disk, we will try to
10182 decrypt it using KEY1 whereas page was encrypted with KEY2. ERROR.
10183 - So don't overwrite keys on tablespace in this scenario.
10184
10185 Case 2:
10186 - Before crash, if tablespace pages were not flushed.
10187 - On disk, there may be
10188 - No Key (after decrypt page 0 was flushed)
10189 - KEY1 (after decrypt, page 0 wasn't flushed)
10190 - KEY2. (After 3 starts, page 0 was flushed)
10191 Thus tablespace would have been loaded accordingly.
10192
10193 This function is called only during recovery when a tablespce is loaded.
10194 So we can see the LSN for REDO Entry (recv_sys->keys) and compare it with
10195 the LSN of page 0 and take decision of updating encryption accordingly. */
10196
10197
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (space->m_encryption_metadata.m_key_len == 0 ||
10198
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 45 times.
46 key.lsn > space->m_header_page_flush_lsn) {
10199 /* Key on tablesapce isn't present or old. Update it. */
10200
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 err = fil_set_encryption(space->id, Encryption::AES, key.ptr, key.iv);
10201 } else {
10202 /* Key on tablespace is new. Skip updating. */
10203 }
10204 }
10205
10206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (err != DB_SUCCESS) {
10207 ib::error(ER_IB_MSG_343) << "Can't set encryption information"
10208 << " for tablespace" << space->name << "!";
10209 }
10210
10211 167 ut::free(key.iv);
10212 167 ut::free(key.ptr);
10213
10214 167 key.iv = nullptr;
10215 167 key.ptr = nullptr;
10216
10217 167 key.space_id = std::numeric_limits<space_id_t>::max();
10218 }
10219 311 }
10220
10221 /** Modify table name in Innodb persistent stat tables, if needed. Required
10222 when partitioned table file names from old versions are modified to change
10223 the letter case.
10224 @param[in] old_path path to old file
10225 @param[in] new_path path to new file */
10226 210 static void fil_adjust_partition_stat(const std::string &old_path,
10227 const std::string &new_path) {
10228 char errstr[FN_REFLEN];
10229 210 std::string path;
10230
10231 /* Skip if not IBD file extension. */
10232
5/6
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 194 times.
404 if (!Fil_path::has_suffix(IBD, old_path) ||
10233
2/4
✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 194 times.
194 !Fil_path::has_suffix(IBD, new_path)) {
10234 16 return;
10235 }
10236
10237 /* Check if partitioned table. */
10238
5/6
✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 188 times.
382 if (!dict_name::is_partition(old_path) ||
10239
2/4
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 188 times.
188 !dict_name::is_partition(new_path)) {
10240 6 return;
10241 }
10242
10243 188 std::string old_name;
10244
1/2
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
188 path.assign(old_path);
10245
2/4
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 188 times.
188 if (!Fil_path::parse_file_path(path, IBD, old_name)) {
10246 return;
10247 }
10248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
188 ut_ad(!old_name.empty());
10249
10250 188 std::string new_name;
10251
1/2
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
188 path.assign(new_path);
10252
2/4
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 188 times.
188 if (!Fil_path::parse_file_path(path, IBD, new_name)) {
10253 return;
10254 }
10255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
188 ut_ad(!new_name.empty());
10256
10257 /* Required for case insensitive file system where file path letter case
10258 doesn't matter. We need to keep the name in stat table consistent. */
10259
1/2
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
188 dict_name::rebuild(new_name);
10260
10261
3/4
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 75 times.
188 if (old_name.compare(new_name) != 0) {
10262
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 dict_stats_rename_table(old_name.c_str(), new_name.c_str(), errstr,
10263 sizeof(errstr));
10264 }
10265
4/6
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 188 times.
✓ Branch 5 taken 22 times.
210 }
10266
10267 /** Update the DD if any files were moved to a new location.
10268 Free the Tablespace_files instance.
10269 @param[in] read_only_mode true if InnoDB is started in read only mode.
10270 @return DB_SUCCESS if all OK */
10271 11911 dberr_t Fil_system::prepare_open_for_business(bool read_only_mode) {
10272
4/6
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 11869 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 11911 times.
11911 if (read_only_mode && !m_moved.empty()) {
10273 ib::error(ER_IB_MSG_344)
10274 << m_moved.size() << " files have been relocated"
10275 << " and the server has been started in read"
10276 << " only mode. Cannot update the data dictionary.";
10277
10278 return DB_READ_ONLY;
10279 }
10280
10281
2/4
✓ Branch 0 taken 11911 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11911 times.
✗ Branch 3 not taken.
11911 trx_t *trx = check_trx_exists(current_thd);
10282
10283
1/2
✓ Branch 0 taken 11911 times.
✗ Branch 1 not taken.
11911 TrxInInnoDB trx_in_innodb(trx);
10284
10285 /* The transaction should not be active yet, start it */
10286
10287 11911 trx->isolation_level = trx_t::READ_UNCOMMITTED;
10288
10289
1/2
✓ Branch 0 taken 11911 times.
✗ Branch 1 not taken.
11911 trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE);
10290
10291 11911 size_t count = 0;
10292 11911 size_t failed = 0;
10293 11911 size_t batch_size = 0;
10294 11911 bool print_msg = false;
10295 11911 auto start_time = std::chrono::steady_clock::now();
10296
10297 /* If some file paths have changed then update the DD */
10298
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 11911 times.
12121 for (auto &tablespace : m_moved) {
10299 dberr_t err;
10300
10301
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 auto old_path = std::get<dd_fil::OLD_PATH>(tablespace);
10302
10303
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 auto space_name = std::get<dd_fil::SPACE_NAME>(tablespace);
10304
10305
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 auto new_path = std::get<dd_fil::NEW_PATH>(tablespace);
10306 210 auto object_id = std::get<dd_fil::OBJECT_ID>(tablespace);
10307
10308 /* We already have the space name in system cs. */
10309
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 err = dd_tablespace_rename(object_id, true, space_name.c_str(),
10310 new_path.c_str());
10311
10312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (err != DB_SUCCESS) {
10313 ib::error(ER_IB_MSG_345) << "Unable to update tablespace ID"
10314 << " " << object_id << " "
10315 << " '" << old_path << "' to"
10316 << " '" << new_path << "'";
10317
10318 ++failed;
10319 }
10320
10321 /* Update persistent stat table if table name is modified. */
10322
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 fil_adjust_partition_stat(old_path, new_path);
10323
10324 210 ++count;
10325
10326
3/6
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 210 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 210 times.
210 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
10327 ib::info(ER_IB_MSG_346) << "Processed " << count << "/" << m_moved.size()
10328 << " tablespace paths. Failures " << failed;
10329
10330 start_time = std::chrono::steady_clock::now();
10331 print_msg = true;
10332 }
10333
10334 210 ++batch_size;
10335
10336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (batch_size > 10000) {
10337 innobase_commit_low(trx);
10338
10339 ib::info(ER_IB_MSG_347) << "Committed : " << batch_size;
10340
10341 batch_size = 0;
10342
10343 trx_start_if_not_started_xa(trx, false, UT_LOCATION_HERE);
10344 }
10345 210 }
10346
10347
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 11887 times.
11911 if (batch_size > 0) {
10348
3/6
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
24 ib::info(ER_IB_MSG_348) << "Committed : " << batch_size;
10349 }
10350
10351
1/2
✓ Branch 0 taken 11911 times.
✗ Branch 1 not taken.
11911 innobase_commit_low(trx);
10352
10353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11911 times.
11911 if (print_msg) {
10354 ib::info(ER_IB_MSG_349) << "Updated " << count << " tablespace paths"
10355 << ", failures " << failed;
10356 }
10357
10358
1/2
✓ Branch 0 taken 11911 times.
✗ Branch 1 not taken.
11911 return failed == 0 ? DB_SUCCESS : DB_ERROR;
10359 11911 }
10360
10361 /** Free the Tablespace_files instance.
10362 @param[in] read_only_mode true if InnoDB is started in read only mode.
10363 @return DB_SUCCESS if all OK */
10364 11911 dberr_t fil_open_for_business(bool read_only_mode) {
10365 11911 return fil_system->prepare_open_for_business(read_only_mode);
10366 }
10367
10368 /** Replay a file rename operation for ddl replay.
10369 @param[in] page_id Space ID and first page number in the file
10370 @param[in] old_name old file name
10371 @param[in] new_name new file name
10372 @return whether the operation was successfully applied (the name did not
10373 exist, or new_name did not exist and name was successfully renamed to
10374 new_name) */
10375 774 bool fil_op_replay_rename_for_ddl(const page_id_t &page_id,
10376 const char *old_name, const char *new_name) {
10377 774 space_id_t space_id = page_id.space();
10378
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 fil_space_t *space = fil_space_get(space_id);
10379
10380
5/8
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 758 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 774 times.
774 if (space == nullptr && !fil_system->open_for_recovery(space_id)) {
10381 ib::info(ER_IB_MSG_350)
10382 << "Can not find space with space ID " << space_id
10383 << " when replaying the DDL log "
10384 << "rename from '" << old_name << "' to '" << new_name << "'";
10385
10386 return true;
10387 }
10388
10389
3/6
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 774 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 774 times.
✗ Branch 5 not taken.
774 return fil_op_replay_rename(page_id, old_name, new_name);
10390 }
10391
10392 /** Lookup the tablespace ID for recovery and DDL log apply.
10393 @param[in] space_id Tablespace ID to lookup
10394 @return true if the space ID is known. */
10395 16858180 bool Fil_system::lookup_for_recovery(space_id_t space_id) {
10396
4/6
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16858164 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16858180 times.
16858180 ut_ad(recv_recovery_is_on() || Log_DDL::is_in_recovery());
10397
10398 /* Single threaded code, no need to acquire mutex. */
10399
1/2
✓ Branch 0 taken 16858180 times.
✗ Branch 1 not taken.
16858180 const auto result = get_scanned_filename_by_space_id(space_id);
10400
10401
2/2
✓ Branch 0 taken 16858164 times.
✓ Branch 1 taken 16 times.
16858180 if (recv_recovery_is_on()) {
10402 16858164 const auto &end = recv_sys->deleted.end();
10403
1/2
✓ Branch 0 taken 16858164 times.
✗ Branch 1 not taken.
16858164 const auto &it = recv_sys->deleted.find(space_id);
10404
10405
2/2
✓ Branch 0 taken 1102092 times.
✓ Branch 1 taken 15756072 times.
16858164 if (result.second == nullptr) {
10406 /* If it wasn't deleted after finding it on disk then
10407 we tag it as missing. */
10408
10409
2/2
✓ Branch 0 taken 1102052 times.
✓ Branch 1 taken 40 times.
1102092 if (it == end) {
10410
1/2
✓ Branch 0 taken 1102052 times.
✗ Branch 1 not taken.
1102052 recv_sys->missing_ids.insert(space_id);
10411 }
10412
10413 1102092 return false;
10414 }
10415
10416 /* Check that it wasn't deleted. */
10417
10418 15756072 return (it == end);
10419 }
10420
10421 16 return (result.second != nullptr);
10422 16858180 }
10423
10424 /** Lookup the tablespace ID.
10425 @param[in] space_id Tablespace ID to lookup
10426 @return true if the space ID is known. */
10427 16839547 bool fil_tablespace_lookup_for_recovery(space_id_t space_id) {
10428 16839547 return fil_system->lookup_for_recovery(space_id);
10429 }
10430
10431 18633 dberr_t Fil_system::open_for_recovery(space_id_t space_id) {
10432
4/6
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18617 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18633 times.
18633 ut_ad(recv_recovery_is_on() || Log_DDL::is_in_recovery());
10433
10434
3/4
✓ Branch 0 taken 18633 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 18609 times.
18633 if (!lookup_for_recovery(space_id)) {
10435 24 return DB_FAIL;
10436 }
10437
10438
1/2
✓ Branch 0 taken 18609 times.
✗ Branch 1 not taken.
18609 const auto result = get_scanned_filename_by_space_id(space_id);
10439
10440 /* Duplicates should have been sorted out before start of recovery. */
10441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18609 times.
18609 ut_a(result.second->size() == 1);
10442
10443 18609 const auto &filename = result.second->front();
10444
1/2
✓ Branch 0 taken 18609 times.
✗ Branch 1 not taken.
18609 const std::string path = result.first + filename;
10445
10446 fil_space_t *space;
10447
10448
1/2
✓ Branch 0 taken 18609 times.
✗ Branch 1 not taken.
18609 auto status = ibd_open_for_recovery(space_id, path, space);
10449
10450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18609 times.
18609 if (status == FIL_LOAD_DBWLR_CORRUPTION) {
10451 return DB_CORRUPTION;
10452 }
10453
10454 18609 dberr_t err = DB_SUCCESS;
10455
10456
2/2
✓ Branch 0 taken 18597 times.
✓ Branch 1 taken 12 times.
18609 if (status == FIL_LOAD_OK) {
10457 18597 if ((FSP_FLAGS_GET_ENCRYPTION(space->flags) ||
10458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16829 times.
16829 space->encryption_op_in_progress ==
10459
4/4
✓ Branch 0 taken 16829 times.
✓ Branch 1 taken 1768 times.
✓ Branch 2 taken 311 times.
✓ Branch 3 taken 18286 times.
37194 Encryption::Progress::ENCRYPTION) &&
10460
2/2
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 1457 times.
1768 recv_sys->keys != nullptr) {
10461
1/2
✓ Branch 0 taken 311 times.
✗ Branch 1 not taken.
311 fil_tablespace_encryption_init(space);
10462 }
10463
10464
1/2
✓ Branch 0 taken 18597 times.
✗ Branch 1 not taken.
18597 if (!recv_sys->dblwr->empty()) {
10465 18597 err = recv_sys->dblwr->recover(space);
10466
10467 } else {
10468 ib::info(ER_IB_MSG_DBLWR_1317) << "DBLWR recovery skipped for "
10469 << space->name << " ID: " << space->id;
10470 }
10471
10472 18597 return err;
10473 }
10474
10475 12 return DB_FAIL;
10476 18609 }
10477
10478 18617 dberr_t fil_tablespace_open_for_recovery(space_id_t space_id) {
10479 18617 return fil_system->open_for_recovery(space_id);
10480 }
10481
10482 104618 Fil_state fil_tablespace_path_equals(space_id_t space_id,
10483 const char *space_name, ulint fsp_flags,
10484 std::string old_path,
10485 std::string *new_path) {
10486
8/14
✓ Branch 0 taken 104618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81268 times.
✓ Branch 3 taken 23350 times.
✓ Branch 4 taken 81268 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 81268 times.
✓ Branch 8 taken 23350 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 23350 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 104618 times.
104618 ut_ad((fsp_is_ibd_tablespace(space_id) &&
10487 Fil_path::has_suffix(IBD, old_path)) ||
10488 fsp_is_undo_tablespace(space_id));
10489
10490 /* Watch out for implicit undo tablespaces that are created during startup.
10491 They will not be in the list of scanned files. But the DD might need to be
10492 updated if the undo directory is different now from when the database was
10493 initialized. The DD will be updated if we put it in fil_system->moved. */
10494
3/4
✓ Branch 0 taken 104618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23350 times.
✓ Branch 3 taken 81268 times.
104618 if (fsp_is_undo_tablespace(space_id)) {
10495
1/2
✓ Branch 0 taken 23350 times.
✗ Branch 1 not taken.
23350 undo::spaces->s_lock();
10496 23350 space_id_t space_num = undo::id2num(space_id);
10497
1/2
✓ Branch 0 taken 23350 times.
✗ Branch 1 not taken.
23350 undo::Tablespace *undo_space = undo::spaces->find(space_num);
10498
10499
6/6
✓ Branch 0 taken 23347 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 23325 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 23328 times.
23350 if (undo_space != nullptr && undo_space->is_new()) {
10500
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 *new_path = undo_space->file_name();
10501
3/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 4 times.
22 Fil_state state = ((old_path.compare(*new_path) == 0) ? Fil_state::MATCHES
10502 22 : Fil_state::MOVED);
10503
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 undo::spaces->s_unlock();
10504 22 return state;
10505 }
10506
1/2
✓ Branch 0 taken 23328 times.
✗ Branch 1 not taken.
23328 undo::spaces->s_unlock();
10507 }
10508
10509 /* Single threaded code, no need to acquire mutex. */
10510 104596 const auto &end = recv_sys->deleted.end();
10511
1/2
✓ Branch 0 taken 104596 times.
✗ Branch 1 not taken.
104596 const auto &it = recv_sys->deleted.find(space_id);
10512
1/2
✓ Branch 0 taken 104596 times.
✗ Branch 1 not taken.
104596 const auto result = fil_system->get_scanned_filename_by_space_id(space_id);
10513
10514
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 104555 times.
104596 if (result.second == nullptr) {
10515 /* The file was not scanned but the DD has the tablespace. Either;
10516 1. This file is missing
10517 2. The file could not be opened because of encryption or something else,
10518 3. The path is not included in --innodb-directories.
10519 We need to check if the DD path is valid before we tag the file
10520 as missing. */
10521
10522
3/4
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 21 times.
41 if (Fil_path::get_file_type(old_path) == OS_FILE_TYPE_FILE) {
10523 /* This file from the DD exists where the DD thinks it is. It will be
10524 opened later. Make some noise if the location is unknown. */
10525
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (!fil_path_is_known(old_path)) {
10526
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 ib::warn(ER_IB_MSG_UNPROTECTED_LOCATION_ALLOWED, old_path.c_str(),
10527 space_name);
10528 }
10529 20 return Fil_state::MATCHES;
10530 }
10531
10532 /* If it wasn't deleted during redo apply, we tag it as missing. */
10533
10534
3/6
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
21 if (it == end && recv_recovery_is_on()) {
10535 recv_sys->missing_ids.insert(space_id);
10536 }
10537
10538 21 return Fil_state::MISSING;
10539 }
10540
10541 /* Check if it was deleted according to the redo log. */
10542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104555 times.
104555 if (it != end) {
10543 return Fil_state::DELETED;
10544 }
10545
10546 /* A file with this space_id was found during scanning.
10547 Validate its location and check if it was moved from where
10548 the DD thinks it is.
10549
10550 Don't compare the full filename, there can be a mismatch if
10551 there was a DDL in progress and we will end up renaming the path
10552 in the DD dictionary. Such renames should be handled by the
10553 atomic DDL "ddl_log". */
10554
10555
1/2
✓ Branch 0 taken 104555 times.
✗ Branch 1 not taken.
104555 std::string old_dir{old_path};
10556
10557 /* Ignore the filename component of the old path. */
10558 104555 auto pos = old_dir.find_last_of(Fil_path::SEPARATOR);
10559
2/2
✓ Branch 0 taken 12289 times.
✓ Branch 1 taken 92266 times.
104555 if (pos == std::string::npos) {
10560
1/2
✓ Branch 0 taken 12289 times.
✗ Branch 1 not taken.
12289 old_dir = MySQL_datadir_path;
10561 } else {
10562
1/2
✓ Branch 0 taken 92266 times.
✗ Branch 1 not taken.
92266 old_dir.resize(pos + 1);
10563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 92266 times.
92266 ut_ad(Fil_path::is_separator(old_dir.back()));
10564 }
10565
1/2
✓ Branch 0 taken 104555 times.
✗ Branch 1 not taken.
104555 old_dir = Fil_path::get_real_path(old_dir);
10566
10567 /* Build the new path from the scan path and the found path. */
10568
1/2
✓ Branch 0 taken 104555 times.
✗ Branch 1 not taken.
104555 std::string new_dir{result.first};
10569
10570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104555 times.
104555 ut_ad(Fil_path::is_separator(new_dir.back()));
10571
10572
1/2
✓ Branch 0 taken 104555 times.
✗ Branch 1 not taken.
104555 new_dir.append(result.second->front());
10573
10574
1/2
✓ Branch 0 taken 104555 times.
✗ Branch 1 not taken.
104555 new_dir = Fil_path::get_real_path(new_dir);
10575
10576 /* Do not use a datafile that is in the wrong place. */
10577
3/4
✓ Branch 0 taken 104555 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 104357 times.
104555 if (!Fil_path::is_valid_location(space_name, space_id, fsp_flags, new_dir)) {
10578 198 return Fil_state::MISSING;
10579 }
10580
10581 /* Ignore the filename component of the new path. */
10582 104357 pos = new_dir.find_last_of(Fil_path::SEPARATOR);
10583
10584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104357 times.
104357 ut_ad(pos != std::string::npos);
10585
10586
1/2
✓ Branch 0 taken 104357 times.
✗ Branch 1 not taken.
104357 new_dir.resize(pos + 1);
10587
10588
3/4
✓ Branch 0 taken 104357 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 79 times.
✓ Branch 3 taken 104278 times.
104357 if (old_dir.compare(new_dir) != 0) {
10589
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 *new_path = result.first + result.second->front();
10590 79 return Fil_state::MOVED;
10591 }
10592
10593
1/2
✓ Branch 0 taken 104278 times.
✗ Branch 1 not taken.
104278 *new_path = old_path;
10594 104278 return Fil_state::MATCHES;
10595 104596 }
10596
10597 210 void fil_add_moved_space(dd::Object_id dd_object_id, space_id_t space_id,
10598 const char *space_name, const std::string &old_path,
10599 const std::string &new_path) {
10600 /* Keep space_name in system cs. We handle it while modifying DD. */
10601 210 fil_system->moved(dd_object_id, space_id, space_name, old_path, new_path);
10602 210 }
10603
10604 315119 bool fil_update_partition_name(space_id_t space_id, uint32_t fsp_flags,
10605 bool update_space, std::string &space_name,
10606 std::string &dd_path) {
10607 #ifdef _WIN32
10608 /* Safe check. Never needed on Windows for path. */
10609 if (!update_space) {
10610 return false;
10611 }
10612 #endif /* WIN32 */
10613
10614 /* Never needed in case insensitive file system for path. */
10615
3/4
✓ Branch 0 taken 203735 times.
✓ Branch 1 taken 111384 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 203735 times.
315119 if (!update_space && lower_case_file_system) {
10616 return false;
10617 }
10618
10619 /* Only needed for file per table. */
10620
7/8
✓ Branch 0 taken 111384 times.
✓ Branch 1 taken 203735 times.
✓ Branch 2 taken 111384 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 35374 times.
✓ Branch 5 taken 76010 times.
✓ Branch 6 taken 35374 times.
✓ Branch 7 taken 279745 times.
315119 if (update_space && !fsp_is_file_per_table(space_id, fsp_flags)) {
10621 35374 return false;
10622 }
10623
10624 /* Extract dictionary name schema_name/table_name from dd path. */
10625 279745 std::string table_name;
10626
10627
3/4
✓ Branch 0 taken 279745 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1237 times.
✓ Branch 3 taken 278508 times.
279745 if (!Fil_path::parse_file_path(dd_path, IBD, table_name)) {
10628 /* Not a valid file-per-table IBD path */
10629 1237 return false;
10630 }
10631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 278508 times.
278508 ut_ad(!table_name.empty());
10632
10633 /* Only needed for partition file. */
10634
3/4
✓ Branch 0 taken 278508 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 250280 times.
✓ Branch 3 taken 28228 times.
278508 if (!dict_name::is_partition(table_name)) {
10635 250280 return false;
10636 }
10637
10638 /* Rebuild dictionary name to convert partition names to lower case. */
10639
1/2
✓ Branch 0 taken 28228 times.
✗ Branch 1 not taken.
28228 dict_name::rebuild(table_name);
10640
10641
2/2
✓ Branch 0 taken 4709 times.
✓ Branch 1 taken 23519 times.
28228 if (update_space) {
10642 /* Rebuild space name if required. */
10643
1/2
✓ Branch 0 taken 4709 times.
✗ Branch 1 not taken.
4709 dict_name::rebuild_space(table_name, space_name);
10644 }
10645
10646 /* No need to update file name for lower case file system. */
10647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28228 times.
28228 if (lower_case_file_system) {
10648 return false;
10649 }
10650
10651 /* Rebuild path and compare. */
10652
1/2
✓ Branch 0 taken 28228 times.
✗ Branch 1 not taken.
28228 std::string table_path = Fil_path::make_new_path(dd_path, table_name, IBD);
10653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28228 times.
28228 ut_ad(!table_path.empty());
10654
10655
3/4
✓ Branch 0 taken 28228 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 770 times.
✓ Branch 3 taken 27458 times.
28228 if (dd_path.compare(table_path) != 0) {
10656 /* Validate that the file exists. */
10657
3/4
✓ Branch 0 taken 770 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 758 times.
✓ Branch 3 taken 12 times.
770 if (os_file_exists(table_path.c_str())) {
10658
1/2
✓ Branch 0 taken 758 times.
✗ Branch 1 not taken.
758 dd_path.assign(table_path);
10659 758 return true;
10660
10661 } else {
10662
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 ib::warn(ER_IB_WARN_OPEN_PARTITION_FILE, table_path.c_str());
10663 }
10664 }
10665
10666 27470 return false;
10667 279745 }
10668
10669 #endif /* !UNIV_HOTBACKUP */
10670
10671 /** This function should be called after recovery has completed.
10672 Check for tablespace files for which we did not see any MLOG_FILE_DELETE
10673 or MLOG_FILE_RENAME record. These could not be recovered.
10674 @return true if there were some filenames missing for which we had to
10675 ignore redo log records during the apply phase */
10676 11610 bool Fil_system::check_missing_tablespaces() {
10677 11610 bool missing = false;
10678 11610 const auto end = recv_sys->deleted.end();
10679
10680 /* Called in single threaded mode, no need to acquire the mutex. */
10681
10682 11610 recv_sys->dblwr->check_missing_tablespaces();
10683
10684
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 11610 times.
11615 for (auto space_id : recv_sys->missing_ids) {
10685
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (recv_sys->deleted.find(space_id) != end) {
10686 continue;
10687 }
10688
10689
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 const auto result = get_scanned_filename_by_space_id(space_id);
10690
10691
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (result.second == nullptr) {
10692
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (fsp_is_undo_tablespace(space_id)) {
10693 /* This could happen if an undo truncate is in progress because
10694 undo tablespace construction is not redo logged. The DD is updated
10695 at the end and may be out of sync. */
10696 continue;
10697 }
10698
10699
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
10 ib::error(ER_IB_MSG_354) << "Could not find any file associated with"
10700
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 << " the tablespace ID: " << space_id;
10701 5 missing = true;
10702
10703 } else {
10704 ut_a(!result.second->empty());
10705 }
10706
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 }
10707
10708 11610 return missing;
10709 }
10710
10711 /** This function should be called after recovery has completed.
10712 Check for tablespace files for which we did not see any MLOG_FILE_DELETE
10713 or MLOG_FILE_RENAME record. These could not be recovered
10714 @return true if there were some filenames missing for which we had to
10715 ignore redo log records during the apply phase */
10716 11610 bool fil_check_missing_tablespaces() {
10717 11610 return fil_system->check_missing_tablespaces();
10718 }
10719
10720 /** Redo a tablespace create.
10721 @param[in] ptr redo log record
10722 @param[in] end end of the redo log buffer
10723 @param[in] page_id Tablespace Id and first page in file
10724 @param[in] parsed_bytes Number of bytes parsed so far
10725 @param[in] parse_only Don't apply, parse only
10726 @return pointer to next redo log record
10727 @retval nullptr if this log record was truncated */
10728 4900 byte *fil_tablespace_redo_create(byte *ptr, const byte *end,
10729 const page_id_t &page_id, ulint parsed_bytes,
10730 bool parse_only) {
10731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4900 times.
4900 ut_a(page_id.page_no() == 0);
10732
10733 /* We never recreate the system tablespace. */
10734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4900 times.
4900 ut_a(page_id.space() != TRX_SYS_SPACE);
10735
10736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4900 times.
4900 ut_a(parsed_bytes != ULINT_UNDEFINED);
10737
10738 /* Where 6 = flags (uint32_t) + name len (uint16_t). */
10739
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4899 times.
4900 if (end <= ptr + 6) {
10740 1 return nullptr;
10741 }
10742
10743 #ifdef UNIV_HOTBACKUP
10744 uint32_t flags = mach_read_from_4(ptr);
10745 #else
10746 /* Skip the flags, not used here. */
10747 #endif /* UNIV_HOTBACKUP */
10748
10749 4899 ptr += 4;
10750
10751 4899 ulint len = mach_read_from_2(ptr);
10752
10753 4899 ptr += 2;
10754
10755 /* Do we have the full/valid file name. */
10756
3/4
✓ Branch 0 taken 4896 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4896 times.
4899 if (end < ptr + len || len < 5) {
10757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (len < 5) {
10758 char name[6];
10759
10760 snprintf(name, sizeof(name), "%.*s", (int)len, ptr);
10761
10762 ib::error(ER_IB_MSG_355) << "MLOG_FILE_CREATE : Invalid file name."
10763 << " Length (" << len << ") must be >= 5"
10764 << " and end in '.ibd'. File name in the"
10765 << " redo log is '" << name << "'";
10766
10767 recv_sys->found_corrupt_log = true;
10768 }
10769
10770 3 return nullptr;
10771 }
10772
10773 4896 char *name = reinterpret_cast<char *>(ptr);
10774
10775 4896 Fil_path::normalize(name);
10776
10777 4896 ptr += len;
10778
10779
7/16
✓ Branch 0 taken 4896 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4896 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 4871 times.
✓ Branch 6 taken 4896 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4896 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4896 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
4921 if (!(Fil_path::has_suffix(IBD, name) ||
10780
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
25 fsp_is_undo_tablespace(page_id.space()))) {
10781 recv_sys->found_corrupt_log = true;
10782
10783 return nullptr;
10784 }
10785
10786
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4894 times.
4896 if (parse_only) {
10787 2 return ptr;
10788 }
10789 #ifdef UNIV_HOTBACKUP
10790
10791 meb_tablespace_redo_create(page_id, flags, name);
10792
10793 #else /* !UNIV_HOTBACKUP */
10794
10795 /* The first condition is true during normal server operation, the
10796 second one during server startup after
10797 recv_recovery_from_checkpoint_start has completed. */
10798
3/6
✓ Branch 0 taken 4894 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4894 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4894 times.
4894 if (!recv_recovery_is_on() || recv_lsn_checks_on) {
10799 /* We are being called from online log tracking, file name
10800 processing is a no-op, and specifically do not cause any DD
10801 changes. */
10802 return (ptr);
10803 }
10804
10805 const auto result =
10806
1/2
✓ Branch 0 taken 4894 times.
✗ Branch 1 not taken.
4894 fil_system->get_scanned_filename_by_space_id(page_id.space());
10807
10808
2/2
✓ Branch 0 taken 1219 times.
✓ Branch 1 taken 3675 times.
4894 if (result.second == nullptr) {
10809 /* No file maps to this tablespace ID. It's possible that
10810 the file was deleted later or is misisng. */
10811
10812 1219 return ptr;
10813 }
10814
10815 /* Update filename with correct partition case, if needed. */
10816
1/2
✓ Branch 0 taken 3675 times.
✗ Branch 1 not taken.
3675 std::string name_str(name);
10817 3675 std::string space_name;
10818
1/2
✓ Branch 0 taken 3675 times.
✗ Branch 1 not taken.
3675 fil_update_partition_name(page_id.space(), 0, false, space_name, name_str);
10819
10820
1/2
✓ Branch 0 taken 3675 times.
✗ Branch 1 not taken.
3675 auto abs_name = Fil_path::get_real_path(name_str);
10821
10822 /* Duplicates should have been sorted out before we get here. */
10823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3675 times.
3675 ut_a(result.second->size() == 1);
10824
10825 /* It's possible that the tablespace file was renamed later. */
10826
2/4
✓ Branch 0 taken 3675 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3675 times.
3675 if (result.second->front().compare(abs_name) == 0) {
10827 dberr_t success = fil_tablespace_open_for_recovery(page_id.space());
10828
10829 if (success != DB_SUCCESS) {
10830 ib::info(ER_IB_MSG_356) << "Create '" << abs_name << "' failed!";
10831 }
10832 }
10833 #endif /* UNIV_HOTBACKUP */
10834
10835 3675 return ptr;
10836 4894 }
10837
10838 2304 byte *fil_tablespace_redo_rename(byte *ptr, const byte *end,
10839 const page_id_t &page_id, ulint parsed_bytes,
10840 bool parse_only [[maybe_unused]]) {
10841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2304 times.
2304 ut_a(page_id.page_no() == 0);
10842
10843 /* We never recreate the system tablespace. */
10844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2304 times.
2304 ut_a(page_id.space() != TRX_SYS_SPACE);
10845
10846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2304 times.
2304 ut_a(parsed_bytes != ULINT_UNDEFINED);
10847
10848 /* Where 2 = from name len (uint16_t). */
10849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2304 times.
2304 if (end <= ptr + 2) {
10850 return nullptr;
10851 }
10852
10853 /* Read and check the RENAME FROM_NAME. */
10854 2304 ulint from_len = mach_read_from_2(ptr);
10855 2304 ptr += 2;
10856 2304 char *from_name = reinterpret_cast<char *>(ptr);
10857
10858 /* Check if the 'from' file name is valid. */
10859
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2303 times.
2304 if (end < ptr + from_len) {
10860 1 return nullptr;
10861 }
10862
10863 2303 std::string whats_wrong;
10864 2303 constexpr char more_than_five[] = "The length must be >= 5.";
10865 2303 constexpr char end_with_ibd[] = "The file suffix must be '.ibd'.";
10866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2303 times.
2303 if (from_len < 5) {
10867 recv_sys->found_corrupt_log = true;
10868 whats_wrong.assign(more_than_five);
10869 } else {
10870
1/2
✓ Branch 0 taken 2303 times.
✗ Branch 1 not taken.
2303 std::string name{from_name};
10871
10872
2/4
✓ Branch 0 taken 2303 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2303 times.
2303 if (!Fil_path::has_suffix(IBD, name)) {
10873 recv_sys->found_corrupt_log = true;
10874 whats_wrong.assign(end_with_ibd);
10875 }
10876 2303 }
10877
10878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2303 times.
2303 if (recv_sys->found_corrupt_log) {
10879 ib::info(ER_IB_MSG_357) << "MLOG_FILE_RENAME: Invalid {from} file name: '"
10880 << from_name << "'. " << whats_wrong;
10881
10882 return nullptr;
10883 }
10884
10885 2303 ptr += from_len;
10886 2303 Fil_path::normalize(from_name);
10887
10888 /* Read and check the RENAME TO_NAME. */
10889 2303 ulint to_len = mach_read_from_2(ptr);
10890 2303 ptr += 2;
10891 2303 char *to_name = reinterpret_cast<char *>(ptr);
10892
10893 /* Check if the 'to' file name is valid. */
10894
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2302 times.
2303 if (end < ptr + to_len) {
10895 1 return nullptr;
10896 }
10897
10898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2302 times.
2302 if (to_len < 5) {
10899 recv_sys->found_corrupt_log = true;
10900 whats_wrong.assign(more_than_five);
10901 } else {
10902
1/2
✓ Branch 0 taken 2302 times.
✗ Branch 1 not taken.
2302 std::string name{to_name};
10903
10904
2/4
✓ Branch 0 taken 2302 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2302 times.
2302 if (!Fil_path::has_suffix(IBD, name)) {
10905 recv_sys->found_corrupt_log = true;
10906 whats_wrong.assign(end_with_ibd);
10907 }
10908 2302 }
10909
10910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2302 times.
2302 if (recv_sys->found_corrupt_log) {
10911 ib::info(ER_IB_MSG_357) << "MLOG_FILE_RENAME: Invalid {to} file name: '"
10912 << to_name << "'. " << whats_wrong;
10913
10914 return nullptr;
10915 }
10916
10917 2302 ptr += to_len;
10918 2302 Fil_path::normalize(to_name);
10919
10920 #ifdef UNIV_HOTBACKUP
10921
10922 if (!parse_only) {
10923 meb_tablespace_redo_rename(page_id, from_name, to_name);
10924 }
10925
10926 #else /* !UNIV_HOTBACKUP */
10927
10928 /* Update filename with correct partition case, if needed. */
10929
1/2
✓ Branch 0 taken 2302 times.
✗ Branch 1 not taken.
2302 std::string to_name_str(to_name);
10930 2302 std::string space_name;
10931
1/2
✓ Branch 0 taken 2302 times.
✗ Branch 1 not taken.
2302 fil_update_partition_name(page_id.space(), 0, false, space_name, to_name_str);
10932
10933
3/4
✓ Branch 0 taken 432 times.
✓ Branch 1 taken 1870 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 432 times.
2302 if (from_len == to_len && strncmp(to_name, from_name, to_len) == 0) {
10934 ib::error(ER_IB_MSG_360)
10935 << "MLOG_FILE_RENAME: The from and to name are the"
10936 << " same: '" << from_name << "', '" << to_name << "'";
10937
10938 recv_sys->found_corrupt_log = true;
10939
10940 return nullptr;
10941 }
10942
10943 #endif /* UNIV_HOTBACKUP */
10944
10945 2302 return ptr;
10946 2303 }
10947
10948 9552 byte *fil_tablespace_redo_extend(byte *ptr, const byte *end,
10949 const page_id_t &page_id, ulint parsed_bytes,
10950 bool parse_only) {
10951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9552 times.
9552 ut_a(page_id.page_no() == 0);
10952
10953 /* We never recreate the system tablespace. */
10954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9552 times.
9552 ut_a(page_id.space() != TRX_SYS_SPACE);
10955
10956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9552 times.
9552 ut_a(parsed_bytes != ULINT_UNDEFINED);
10957
10958 /* Check for valid offset and size values */
10959
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9549 times.
9552 if (end < ptr + 16) {
10960 3 return nullptr;
10961 }
10962
10963 /* Offset within the file to start writing zeros */
10964
1/2
✓ Branch 0 taken 9549 times.
✗ Branch 1 not taken.
9549 os_offset_t offset = mach_read_from_8(ptr);
10965 9549 ptr += 8;
10966
10967 /* Size of the space which needs to be initialized by
10968 writing zeros */
10969
1/2
✓ Branch 0 taken 9549 times.
✗ Branch 1 not taken.
9549 os_offset_t size = mach_read_from_8(ptr);
10970 9549 ptr += 8;
10971
10972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9549 times.
9549 if (size == 0) {
10973 ib::error(ER_IB_MSG_INCORRECT_SIZE)
10974 << "MLOG_FILE_EXTEND: Incorrect value for size encountered."
10975 << "Redo log corruption found.";
10976 recv_sys->found_corrupt_log = true;
10977 return nullptr;
10978 }
10979
10980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9549 times.
9549 if (parse_only) {
10981 return ptr;
10982 }
10983
10984 #ifndef UNIV_HOTBACKUP
10985 const auto result =
10986
1/2
✓ Branch 0 taken 9549 times.
✗ Branch 1 not taken.
9549 fil_system->get_scanned_filename_by_space_id(page_id.space());
10987
10988
2/2
✓ Branch 0 taken 1930 times.
✓ Branch 1 taken 7619 times.
9549 if (result.second == nullptr) {
10989 /* No files found for this tablespace ID. It's possible that the
10990 files were deleted later. */
10991 1930 return ptr;
10992 }
10993
10994
1/2
✓ Branch 0 taken 7619 times.
✗ Branch 1 not taken.
7619 dberr_t err = fil_tablespace_open_for_recovery(page_id.space());
10995
10996
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7615 times.
7619 if (err != DB_SUCCESS) {
10997 /* fil_tablespace_open_for_recovery may fail if the tablespace being
10998 opened is an undo tablespace which is also marked for truncation.
10999 In such a case, skip processing this redo log further and goto the
11000 next record without doing anything more here. */
11001
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 if (fsp_is_undo_tablespace(page_id.space()) &&
11002 undo::is_active_truncate_log_present(undo::id2num(page_id.space()))) {
11003 return ptr;
11004 }
11005 4 return nullptr;
11006 }
11007
11008 /* Open the space */
11009
1/2
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
7615 bool success = fil_space_open(page_id.space());
11010
11011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 if (!success) {
11012 return nullptr;
11013 }
11014
11015
1/2
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
7615 fil_space_t *space = fil_space_get(page_id.space());
11016
11017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(space != nullptr);
11018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(!space->files.empty());
11019
11020 /* Space extension operations on temporary tablespaces
11021 are not redo logged as they are always recreated on
11022 server startup. */
11023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(space->purpose != FIL_TYPE_TEMPORARY);
11024
11025 7615 fil_node_t *file = &space->files.back();
11026
11027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(file != nullptr);
11028
11029
1/2
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
7615 page_size_t page_size(space->flags);
11030
11031
1/2
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
7615 size_t phy_page_size = page_size.physical();
11032
11033 /* No one else should be extending this file. */
11034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(!file->is_being_extended);
11035
11036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(offset > 0);
11037
1/2
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
7615 os_offset_t initial_fsize = os_file_get_size(file->handle);
11038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(offset <= initial_fsize);
11039 /* file->size unit is FSP_EXTENT_SIZE.
11040 Disk-full might cause partial FSP_EXTENT_SIZE extension. */
11041
3/10
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7615 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 7615 times.
7615 ut_a(initial_fsize / (phy_page_size * FSP_EXTENT_SIZE) ==
11042 file->size / FSP_EXTENT_SIZE);
11043
11044 /* Because punch_hole flush might recover disk-full situation.
11045 We might be able to extend from the partial extension at the
11046 previous disk-full. So, offset might not be at boundary.
11047 But target is aligned to the page boundary */
11048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7615 times.
7615 ut_a(((offset + size) % phy_page_size) == 0);
11049
11050 /* If the physical size of the file is greater than or equal to the
11051 expected size (offset + size), it means that posix_fallocate was
11052 successfully executed.
11053 However, if the redo log record requests an expected size (offset + size)
11054 which is more than the physical size of the file, it means that
11055 posix_fallocate() either allocated partially (in case of emulated
11056 posix_fallocate) or did not allocate at all. In case posix_fallocate()
11057 fails, the server calls fil_write_zeros to extend the space, which
11058 can also fail after allocating space partially because of reasons like
11059 lack of disk space. The real indicator of how much file was actually
11060 allocated is the physical file size itself.
11061 Write out the 0's in the extended space only if the physical size of
11062 the file is less than the expected size (offset + size). */
11063
11064 /* If the file is already equal or larger than the expected size,
11065 nothing more to do here. */
11066
2/2
✓ Branch 0 taken 7499 times.
✓ Branch 1 taken 116 times.
7615 if ((offset + size) <= initial_fsize) {
11067 7499 return ptr;
11068 }
11069
11070 #if defined(UNIV_DEBUG)
11071 /* Validate that there are no pages in the buffer pool. */
11072
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 buf_must_be_all_freed();
11073 #endif /* UNIV_DEBUG */
11074
11075 /* Adjust the actual allocation size to take care of the allocation
11076 problems described above.
11077 Find out the size by which the file should be extended to have
11078 a file of expected size while ensuring that the already allocated
11079 pages are not overwritten with zeros. */
11080 116 os_offset_t new_ext_size = size - (initial_fsize - offset);
11081
11082 /* Initialize the region starting from current end of file with zeros. */
11083
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 err = fil_write_zeros(file, phy_page_size, initial_fsize, new_ext_size);
11084
11085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
116 if (err != DB_SUCCESS) {
11086 /* Error writing zeros to the file. */
11087 ib::warn(ER_IB_MSG_320) << "Error while writing " << size << " zeroes to "
11088 << file->name << " starting at offset " << offset;
11089 /* Should return normally. If "return nullptr", it means "broken log"
11090 and will skip to apply the all of following logs. */
11091 }
11092
11093 /* Get the final size of the file and adjust file->size accordingly. */
11094
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 os_offset_t end_fsize = os_file_get_size(file->handle);
11095
11096 116 file->size = end_fsize / phy_page_size;
11097 116 space->size = file->size;
11098
11099
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 fil_flush(space->id);
11100
11101
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 fil_space_close(space->id);
11102 #endif /* !UNIV_HOTBACKUP */
11103
11104 116 return ptr;
11105 9549 }
11106
11107 /** Redo a tablespace delete.
11108 @param[in] ptr redo log record
11109 @param[in] end end of the redo log buffer
11110 @param[in] page_id Tablespace Id and first page in file
11111 @param[in] parsed_bytes Number of bytes parsed so far
11112 @param[in] parse_only Don't apply, parse only
11113 @return pointer to next redo log record
11114 @retval nullptr if this log record was truncated */
11115 3864 byte *fil_tablespace_redo_delete(byte *ptr, const byte *end,
11116 const page_id_t &page_id, ulint parsed_bytes,
11117 bool parse_only) {
11118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3864 times.
3864 ut_a(page_id.page_no() == 0);
11119
11120 /* We never recreate the system tablespace. */
11121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3864 times.
3864 ut_a(page_id.space() != TRX_SYS_SPACE);
11122
11123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3864 times.
3864 ut_a(parsed_bytes != ULINT_UNDEFINED);
11124
11125 /* Where 2 = len (uint16_t). */
11126
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3863 times.
3864 if (end <= ptr + 2) {
11127 1 return nullptr;
11128 }
11129
11130 3863 ulint len = mach_read_from_2(ptr);
11131
11132 3863 ptr += 2;
11133
11134 /* Do we have the full/valid file name. */
11135
2/4
✓ Branch 0 taken 3863 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3863 times.
3863 if (end < ptr + len || len < 5) {
11136 if (len < 5) {
11137 char name[6];
11138
11139 snprintf(name, sizeof(name), "%.*s", (int)len, ptr);
11140
11141 ib::error(ER_IB_MSG_362) << "MLOG_FILE_DELETE : Invalid file name."
11142 << " Length (" << len << ") must be >= 5"
11143 << " and end in '.ibd'. File name in the"
11144 << " redo log is '" << name << "'";
11145 }
11146
11147 return nullptr;
11148 }
11149
11150 3863 char *name = reinterpret_cast<char *>(ptr);
11151
11152 3863 Fil_path::normalize(name);
11153
11154 3863 ptr += len;
11155
11156
7/16
✓ Branch 0 taken 3863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3863 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 3825 times.
✓ Branch 6 taken 3863 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3863 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 3863 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
3901 if (!(Fil_path::has_suffix(IBD, name) ||
11157
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 fsp_is_undo_tablespace(page_id.space()))) {
11158 recv_sys->found_corrupt_log = true;
11159
11160 return nullptr;
11161 }
11162
11163
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3852 times.
3863 if (parse_only) {
11164 11 return ptr;
11165 }
11166 #ifdef UNIV_HOTBACKUP
11167
11168 meb_tablespace_redo_delete(page_id, name);
11169
11170 #else /* !UNIV_HOTBACKUP */
11171
11172 /* The first condition is true during normal server operation, the
11173 second one during server startup after
11174 recv_recovery_from_checkpoint_start has completed. */
11175
3/6
✓ Branch 0 taken 3852 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3852 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3852 times.
3852 if (!recv_recovery_is_on() || recv_lsn_checks_on) {
11176 /* We are being called from online log tracking, file name
11177 processing is a no-op, and specifically do not cause any DD
11178 changes. */
11179 return (ptr);
11180 }
11181
11182 const auto result =
11183
1/2
✓ Branch 0 taken 3852 times.
✗ Branch 1 not taken.
3852 fil_system->get_scanned_filename_by_space_id(page_id.space());
11184
11185
1/2
✓ Branch 0 taken 3852 times.
✗ Branch 1 not taken.
3852 recv_sys->deleted.insert(page_id.space());
11186
1/2
✓ Branch 0 taken 3852 times.
✗ Branch 1 not taken.
3852 recv_sys->missing_ids.erase(page_id.space());
11187
11188
2/2
✓ Branch 0 taken 3832 times.
✓ Branch 1 taken 20 times.
3852 if (result.second == nullptr) {
11189 /* No files map to this tablespace ID. The drop must
11190 have succeeded. */
11191
11192 3832 return ptr;
11193 }
11194
11195 /* Space_id_set should have been sorted out before we get here. */
11196
11197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 ut_a(result.second->size() == 1);
11198
11199 /* Update filename with correct partition case, if needed. */
11200
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 std::string name_str(name);
11201 20 std::string space_name;
11202
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 fil_update_partition_name(page_id.space(), 0, false, space_name, name_str);
11203
11204
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 fil_space_free(page_id.space(), false);
11205
11206
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 bool success = fil_system->erase_path(page_id.space());
11207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 ut_a(success);
11208 #endif /* UNIV_HOTBACKUP */
11209
11210 20 return ptr;
11211 3852 }
11212
11213 245 byte *fil_tablespace_redo_encryption(byte *ptr, const byte *end,
11214 space_id_t space_id, lsn_t lsn) {
11215
1/2
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
245 fil_space_t *space = fil_space_get(space_id);
11216
11217 /* An undo space might be open but not have the ENCRYPTION bit set
11218 in its header if the current value of innodb_undo_log_encrypt=OFF
11219 and a crash occurred between flushing this redo record and the header
11220 page of the undo space. So if the flag is missing, ignore the header
11221 page. */
11222
5/10
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 235 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 245 times.
245 if (fsp_is_undo_tablespace(space_id) && space != nullptr &&
11223 !FSP_FLAGS_GET_ENCRYPTION(space->flags)) {
11224 space = nullptr;
11225 }
11226
11227 245 ulint offset = mach_read_from_2(ptr);
11228 245 ptr += 2;
11229
11230 245 const ulint len = mach_read_from_2(ptr);
11231 245 ptr += 2;
11232
11233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 if (end < ptr + len) {
11234 return (nullptr);
11235 }
11236
11237
3/6
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 245 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 245 times.
245 if (offset >= UNIV_PAGE_SIZE || len + offset > UNIV_PAGE_SIZE ||
11238 len != Encryption::INFO_SIZE) {
11239 recv_sys->found_corrupt_log = true;
11240 return (nullptr);
11241 }
11242
11243 245 byte *encryption_ptr = ptr;
11244 245 ptr += len;
11245
11246 /* If space is already loaded and have header_page_flushed_lsn greater than
11247 this REDO entry LSN, then skip it coz header has latest information. */
11248
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
245 if (space != nullptr && space->m_header_page_flush_lsn > lsn) {
11249 2 return (ptr);
11250 }
11251
11252 /* If encryption info is 0 filled, then this is erasing encryption info
11253 during unencryption operation. Skip decrypting it. */
11254 {
11255 243 byte buf[Encryption::INFO_SIZE] = {0};
11256
11257
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 209 times.
243 if (memcmp(encryption_ptr + 4, buf, Encryption::INFO_SIZE - 4) == 0) {
11258 /* NOTE: We don't need to reset encryption info of space here because it
11259 might be needed. It will be reset when this REDO record is applied. */
11260 34 return (ptr);
11261 }
11262 }
11263
11264 209 byte iv[Encryption::KEY_LEN] = {0};
11265 209 byte key[Encryption::KEY_LEN] = {0};
11266
11267 209 Encryption_key e_key{key, iv};
11268
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 207 times.
209 if (!Encryption::decode_encryption_info(space_id, e_key, encryption_ptr,
11269 true)) {
11270 2 recv_sys->found_corrupt_log = true;
11271
11272
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 ib::warn(ER_IB_MSG_364)
11273
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 << "Encryption information"
11274
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 << " in the redo log of space " << space_id << " is invalid";
11275
11276 2 return (nullptr);
11277 }
11278
11279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 ut_ad(len == Encryption::INFO_SIZE);
11280
11281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 207 times.
207 if (space != nullptr) {
11282 Encryption::set_or_generate(Encryption::AES, key, iv,
11283 space->m_encryption_metadata);
11284 fsp_flags_set_encryption(space->flags);
11285 return ptr;
11286 }
11287
11288 /* Space is not loaded yet. Remember this key in recv_sys and use it later
11289 to pupulate space encryption info once it is loaded. */
11290
3/4
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 203 times.
207 DBUG_EXECUTE_IF("dont_update_key_found_during_REDO_scan", return ptr;);
11291
11292
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 48 times.
203 if (recv_sys->keys == nullptr) {
11293 310 recv_sys->keys =
11294
1/2
✓ Branch 0 taken 155 times.
✗ Branch 1 not taken.
155 ut::new_withkey<recv_sys_t::Encryption_Keys>(UT_NEW_THIS_FILE_PSI_KEY);
11295 }
11296
11297 /* Search if key entry already exists for this tablespace, update it. */
11298
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 198 times.
274 for (auto &recv_key : *recv_sys->keys) {
11299
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 71 times.
76 if (recv_key.space_id == space_id) {
11300 5 memcpy(recv_key.iv, iv, Encryption::KEY_LEN);
11301 5 memcpy(recv_key.ptr, key, Encryption::KEY_LEN);
11302 5 recv_key.lsn = lsn;
11303 5 return ptr;
11304 }
11305 }
11306
11307 /* No existing entry found, create new one and insert it. */
11308 recv_sys_t::Encryption_Key new_key;
11309 198 new_key.iv = static_cast<byte *>(
11310 198 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, Encryption::KEY_LEN));
11311 198 memcpy(new_key.iv, iv, Encryption::KEY_LEN);
11312 198 new_key.ptr = static_cast<byte *>(
11313 198 ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY, Encryption::KEY_LEN));
11314 198 memcpy(new_key.ptr, key, Encryption::KEY_LEN);
11315 198 new_key.space_id = space_id;
11316 198 new_key.lsn = lsn;
11317
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 recv_sys->keys->push_back(new_key);
11318
11319 198 return ptr;
11320 }
11321
11322 void Tablespace_dirs::warn_ignore(std::string ignore_path, const char *reason) {
11323 ib::warn(ER_IB_MSG_IGNORE_SCAN_PATH, ignore_path.c_str(), reason);
11324 }
11325
11326 24132 void Tablespace_dirs::add_path(const std::string &path_in, bool is_undo_dir) {
11327 /* Ignore an invalid path. */
11328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24132 times.
24132 if (path_in == "") {
11329 return;
11330 }
11331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24132 times.
24132 if (path_in == "/") {
11332 warn_ignore(path_in,
11333 "the root directory '/' is not allowed to be scanned.");
11334 return;
11335 }
11336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24132 times.
24132 if (std::string::npos != path_in.find('*')) {
11337 warn_ignore(path_in, "it contains '*'.");
11338 return;
11339 }
11340
11341 /* Assume this path is a directory and put a trailing slash on it. */
11342
1/2
✓ Branch 0 taken 24132 times.
✗ Branch 1 not taken.
24132 std::string dir_in(path_in);
11343
1/2
✓ Branch 0 taken 24132 times.
✗ Branch 1 not taken.
24132 Fil_path::append_separator(dir_in);
11344
11345
1/2
✓ Branch 0 taken 24132 times.
✗ Branch 1 not taken.
24132 Fil_path found_path(dir_in, true);
11346
11347 /* Exclude this path if it is a duplicate of a path already stored or
11348 if a previously stored path is an ancestor. Remove any previously stored
11349 path that is a descendant of this path. */
11350
2/2
✓ Branch 0 taken 12181 times.
✓ Branch 1 taken 12167 times.
24348 for (auto it = m_dirs.cbegin(); it != m_dirs.cend(); /* No op */) {
11351
3/4
✓ Branch 0 taken 12181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11965 times.
✓ Branch 3 taken 216 times.
12181 if (it->root().is_same_as(found_path)) {
11352 /* The exact same path is obviously ignored, so there is no need to
11353 log a warning. */
11354 11965 return;
11355 }
11356
11357 /* Check if dir_abs_path is an ancestor of this path */
11358
2/4
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 216 times.
216 if (it->root().is_ancestor(found_path)) {
11359 /* Descendant directories will be scanned recursively, so don't
11360 add it to the scan list. Log a warning unless this descendant
11361 is the undo directory since it must be supplied even if it is
11362 a descendant of another data location. */
11363 if (!is_undo_dir) {
11364 std::string reason = "it is a sub-directory of '";
11365 reason += it->root().abs_path();
11366 warn_ignore(path_in, reason.c_str());
11367 }
11368 return;
11369 }
11370
11371
2/4
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 216 times.
216 if (found_path.is_ancestor(it->root())) {
11372 /* This path is an ancestor of an existing dir in fil_system::m_dirs.
11373 The settings have overlapping locations. Put a note about it to
11374 the error log. The undo_dir is added last, so if it is an ancestor,
11375 the descendant was listed as a datafile directory. So always issue
11376 this message*/
11377 std::string reason = "it is a sub-directory of '";
11378 reason += found_path;
11379 warn_ignore(it->root().path(), reason.c_str());
11380
11381 /* It might also be an ancestor to another dir as well, so keep looking.
11382 We must delete this descendant because we know that this ancestor path
11383 will be inserted and all its descendants will be scanned. */
11384 it = m_dirs.erase(it);
11385 } else {
11386 216 it++;
11387 }
11388 }
11389
11390
2/4
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12167 times.
✗ Branch 3 not taken.
12167 m_dirs.push_back(Tablespace_files{found_path.path()});
11391 12167 return;
11392 24132 }
11393
11394 95 void Tablespace_dirs::add_paths(const std::string &str,
11395 const std::string &delimiters) {
11396 95 std::string::size_type start = 0;
11397 95 std::string::size_type end = 0;
11398
11399 /* Scan until 'start' reaches the end of the string (npos) */
11400 for (;;) {
11401 195 start = str.find_first_not_of(delimiters, end);
11402
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 100 times.
195 if (std::string::npos == start) {
11403 95 break;
11404 }
11405
11406 100 end = str.find_first_of(delimiters, start);
11407
11408
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 const auto path = str.substr(start, end - start);
11409
11410
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 add_path(path);
11411 100 }
11412 95 }
11413
11414 /** Check whether we can rename the file
11415 @param[in] space Tablespace for which to rename
11416 @param[in] name Source file name
11417 @param[in] df Target file that exists on disk
11418 @return DB_SUCCESS if all OK */
11419 131 static dberr_t fil_rename_validate(fil_space_t *space, const std::string &name,
11420 Datafile &&df) {
11421 131 dberr_t err = df.validate_for_recovery(space->id).error;
11422 /* The validate_for_recovery will set space_id, but will close the file. It is
11423 safe to access filepath and space_id. */
11424
11425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (err == DB_TABLESPACE_NOT_FOUND) {
11426 /* Tablespace header doesn't contain the expected
11427 tablespace ID. This is can happen during truncate. */
11428
11429 return err;
11430
11431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 } else if (err != DB_SUCCESS) {
11432 ib::warn(ER_IB_MSG_367) << "Failed to read the first page of the"
11433 << " file '" << df.filepath() << "'."
11434 << " You will need to verify and move the"
11435 << " file out of the way retry recovery.";
11436
11437 return err;
11438 }
11439
11440 131 auto file = &space->files.front();
11441
11442
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 if (strcmp(df.filepath(), file->name) == 0) {
11443 /* Check if already points to the correct file.
11444 Must have the same space ID */
11445
11446
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 ib::info(ER_IB_MSG_368) << "Tablespace ID already maps to: '"
11447
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
131 << df.filepath() << "', rename ignored.";
11448
11449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 ut_a(df.space_id() == space->id);
11450
11451 131 return DB_SUCCESS;
11452
11453 } else if (df.space_id() != space->id) {
11454 /* Target file exists on disk but has a different
11455 tablespace ID. The user should manually delete it. */
11456
11457 ib::error(ER_IB_MSG_369)
11458 << "Cannot rename '" << name << "' to '" << df.filepath() << "'. File '"
11459 << df.filepath() << "' tablespace ID " << df.space_id()
11460 << " doesn't match the expected tablespace"
11461 << " ID " << space->id << ". You will need to verify and move '"
11462 << df.filepath() << "' manually and retry recovery!";
11463
11464 return DB_ERROR;
11465 }
11466
11467 /* Target file exists on disk and has the same ID. */
11468
11469 ib::error(ER_IB_MSG_370)
11470 << "Cannot rename '" << name << "' to '" << df.filepath()
11471 << "'. The File '" << df.filepath() << " already exists on"
11472 << " disk. You will need to verify and move either file"
11473 << " manually and retry recovery!";
11474
11475 return DB_ERROR;
11476 }
11477
11478 /** Replay a file rename operation if possible.
11479 @param[in] page_id Space ID and first page number in the file
11480 @param[in] old_name old file name
11481 @param[in] new_name new file name
11482 @return whether the operation was successfully applied (the name did not exist,
11483 or new_name did not exist and name was successfully renamed to new_name) */
11484 774 static bool fil_op_replay_rename(const page_id_t &page_id,
11485 const std::string &old_name,
11486 const std::string &new_name) {
11487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 774 times.
774 ut_ad(page_id.page_no() == 0);
11488
2/4
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 774 times.
774 ut_ad(old_name.compare(new_name) != 0);
11489
2/4
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 774 times.
774 ut_ad(Fil_path::has_suffix(IBD, new_name));
11490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 774 times.
774 ut_ad(page_id.space() != TRX_SYS_SPACE);
11491
11492 /* In order to replay the rename, the following must hold:
11493 1. The new name is not already used.
11494 2. A tablespace exists with the old name.
11495 3. The space ID for that tablespace matches this log entry.
11496 This will prevent unintended renames during recovery. */
11497
11498 774 space_id_t space_id = page_id.space();
11499
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 fil_space_t *space = fil_space_get(space_id);
11500
11501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 774 times.
774 if (space == nullptr) {
11502 return true;
11503 }
11504
11505
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 std::string name{new_name};
11506 {
11507 774 Datafile df;
11508
11509
1/2
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
774 df.set_filepath(name.c_str());
11510
11511
3/4
✓ Branch 0 taken 774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✓ Branch 3 taken 643 times.
774 if (df.open_read_only(false) == DB_SUCCESS) {
11512
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 dberr_t err = fil_rename_validate(space, old_name, std::move(df));
11513
11514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (err == DB_TABLESPACE_NOT_FOUND) {
11515 /* This can happen during truncate. */
11516 ib::info(ER_IB_MSG_371) << "Tablespace ID mismatch in '" << name << "'";
11517 }
11518 131 return (err == DB_SUCCESS);
11519 }
11520
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 131 times.
774 }
11521
11522 643 auto path_sep_pos = name.find_last_of(Fil_path::SEPARATOR);
11523
11524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 643 times.
643 ut_a(path_sep_pos != std::string::npos);
11525
11526 /* Create the database directory for the new name, if
11527 it does not exist yet */
11528
11529
1/2
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
643 name.resize(path_sep_pos);
11530
11531
1/2
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
643 bool success = os_file_create_directory(name.c_str(), false);
11532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 643 times.
643 ut_a(success);
11533
11534 643 auto datadir_pos = name.find_last_of(Fil_path::SEPARATOR);
11535
11536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 643 times.
643 ut_ad(datadir_pos != std::string::npos);
11537
11538
1/2
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
643 name.erase(0, datadir_pos + 1);
11539
11540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 643 times.
643 ut_ad(!Fil_path::is_separator(name.back()));
11541
11542 /* schema/table separator is always a '/'. */
11543
1/2
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
643 name.push_back('/');
11544
11545 /* Strip the '.ibd' suffix. */
11546
1/2
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
643 name.append(new_name.begin() + path_sep_pos + 1, new_name.end() - 4);
11547
11548
2/4
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 643 times.
643 ut_ad(!Fil_path::has_suffix(IBD, name));
11549
11550 643 const auto ptr = name.c_str();
11551
11552 dberr_t err =
11553
1/2
✓ Branch 0 taken 643 times.
✗ Branch 1 not taken.
643 fil_rename_tablespace(space_id, old_name.c_str(), ptr, new_name.c_str());
11554
11555 /* Stop recovery if this does not succeed. */
11556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 643 times.
643 ut_a(err == DB_SUCCESS);
11557
11558 643 return true;
11559 774 }
11560
11561 /** Get the tablespace ID from an .ibd and/or an undo tablespace. If the ID is 0
11562 on the first page then try finding the ID with Datafile::find_space_id().
11563 @param[in] filename File name to check
11564 @return s_invalid_space_id if not found, otherwise the space ID */
11565 110309 space_id_t Fil_system::get_tablespace_id(const std::string &filename) {
11566
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 FILE *fp = fopen(filename.c_str(), "rb");
11567
11568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110309 times.
110309 if (fp == nullptr) {
11569 ib::warn(ER_IB_MSG_372) << "Unable to open '" << filename << "'";
11570 return dict_sys_t::s_invalid_space_id;
11571 }
11572
11573 110309 std::vector<space_id_t> space_ids;
11574 110309 auto page_size = srv_page_size;
11575
11576
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 space_ids.reserve(MAX_PAGES_TO_READ);
11577
11578 110309 const auto n_bytes = page_size * MAX_PAGES_TO_READ;
11579
11580
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 std::unique_ptr<byte[]> buf(new byte[n_bytes]);
11581
11582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110309 times.
110309 if (!buf) {
11583 return dict_sys_t::s_invalid_space_id;
11584 }
11585
11586
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 auto pages_read = fread(buf.get(), page_size, MAX_PAGES_TO_READ, fp);
11587
11588
2/4
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 110309 times.
110309 DBUG_EXECUTE_IF("invalid_header", pages_read = 0;);
11589
11590 /* Find the space id from the pages read if enough pages could be read.
11591 Fall back to the more heavier method of finding the space id from
11592 Datafile::find_space_id() if pages cannot be read properly. */
11593
2/2
✓ Branch 0 taken 110286 times.
✓ Branch 1 taken 23 times.
110309 if (pages_read >= MAX_PAGES_TO_READ) {
11594 110286 auto bytes_read = pages_read * page_size;
11595
11596 #ifdef POSIX_FADV_DONTNEED
11597 110286 posix_fadvise(fileno(fp), 0, bytes_read, POSIX_FADV_DONTNEED);
11598 #endif /* POSIX_FADV_DONTNEED */
11599
11600
2/2
✓ Branch 0 taken 110286 times.
✓ Branch 1 taken 240 times.
110526 for (page_no_t i = 0; i < MAX_PAGES_TO_READ; ++i) {
11601 110286 const auto off = i * page_size + FIL_PAGE_SPACE_ID;
11602
11603
1/2
✓ Branch 0 taken 110286 times.
✗ Branch 1 not taken.
110286 if (off == FIL_PAGE_SPACE_ID) {
11604 /* Find out the page size of the tablespace from the first page.
11605 In case of compressed pages, the subsequent pages can be of different
11606 sizes. If MAX_PAGES_TO_READ is changed to a different value, then the
11607 page size of subsequent pages is needed to find out the offset for
11608 space ID. */
11609
11610 110286 auto space_flags_offset = FSP_HEADER_OFFSET + FSP_SPACE_FLAGS;
11611
11612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110286 times.
110286 ut_a(space_flags_offset + 4 < n_bytes);
11613
11614
1/2
✓ Branch 0 taken 110286 times.
✗ Branch 1 not taken.
110286 const auto flags = mach_read_from_4(buf.get() + space_flags_offset);
11615
11616
1/2
✓ Branch 0 taken 110286 times.
✗ Branch 1 not taken.
110286 page_size_t space_page_size(flags);
11617
11618
1/2
✓ Branch 0 taken 110286 times.
✗ Branch 1 not taken.
110286 page_size = space_page_size.physical();
11619 }
11620
11621
2/4
✓ Branch 0 taken 110286 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110286 times.
✗ Branch 3 not taken.
110286 space_ids.push_back(mach_read_from_4(buf.get() + off));
11622
11623
2/2
✓ Branch 0 taken 110046 times.
✓ Branch 1 taken 240 times.
110286 if ((i + 1) * page_size >= bytes_read) {
11624 110046 break;
11625 }
11626 }
11627 }
11628
11629
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 fclose(fp);
11630
11631 space_id_t space_id;
11632
11633
2/2
✓ Branch 0 taken 110286 times.
✓ Branch 1 taken 23 times.
110309 if (!space_ids.empty()) {
11634 110286 space_id = space_ids.front();
11635
11636
2/2
✓ Branch 0 taken 110286 times.
✓ Branch 1 taken 110276 times.
220562 for (auto id : space_ids) {
11637
3/4
✓ Branch 0 taken 110276 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 110276 times.
110286 if (id == 0 || space_id != id) {
11638 10 space_id = UINT32_UNDEFINED;
11639
11640 10 break;
11641 }
11642 }
11643 } else {
11644 23 space_id = UINT32_UNDEFINED;
11645 }
11646
11647 /* Try the more heavy duty method, as a last resort. */
11648
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 110276 times.
110309 if (space_id == UINT32_UNDEFINED) {
11649 /* If the first page cannot be read properly, then for compressed
11650 tablespaces we don't know where the page boundary starts because
11651 we don't know the page size. */
11652
11653 33 Datafile file;
11654
11655
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 file.set_filepath(filename.c_str());
11656
11657
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 dberr_t err = file.open_read_only(false);
11658
11659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 ut_a(file.is_open());
11660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 ut_a(err == DB_SUCCESS);
11661
11662 /* Use the heavier Datafile::find_space_id() method to
11663 find the space id. */
11664
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 err = file.find_space_id();
11665
11666
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (err == DB_SUCCESS) {
11667 33 space_id = file.space_id();
11668 }
11669
11670
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 file.close();
11671 33 }
11672
11673 110309 return space_id;
11674 110309 }
11675
11676 12021 void Fil_system::rename_partition_files(bool revert) {
11677 #ifndef UNIV_HOTBACKUP
11678 /* If revert, then we are downgrading after upgrade failure from 5.7 */
11679
4/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 11994 times.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12021 times.
12021 ut_ad(!revert || srv_downgrade_partition_files);
11680
11681
2/2
✓ Branch 0 taken 11971 times.
✓ Branch 1 taken 50 times.
12021 if (m_old_paths.empty()) {
11682 11971 return;
11683 }
11684
11685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 ut_ad(!lower_case_file_system);
11686
11687
2/2
✓ Branch 0 taken 577 times.
✓ Branch 1 taken 50 times.
627 for (auto &old_path : m_old_paths) {
11688
2/4
✓ Branch 0 taken 577 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 577 times.
577 ut_ad(Fil_path::has_suffix(IBD, old_path));
11689
2/4
✓ Branch 0 taken 577 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 577 times.
577 ut_ad(dict_name::is_partition(old_path));
11690
11691
1/2
✓ Branch 0 taken 577 times.
✗ Branch 1 not taken.
577 fil_rename_partition_file(old_path, IBD, revert, false);
11692 }
11693 #endif /* !UNIV_HOTBACKUP */
11694 }
11695
11696 23694 void Tablespace_dirs::duplicate_check(const Const_iter &start,
11697 const Const_iter &end, size_t thread_id,
11698 std::mutex *mutex, Space_id_set *unique,
11699 Space_id_set *duplicates) {
11700 23694 size_t count = 0;
11701 23694 bool printed_msg = false;
11702 23694 auto start_time = std::chrono::steady_clock::now();
11703
11704
2/2
✓ Branch 0 taken 110309 times.
✓ Branch 1 taken 23694 times.
134003 for (auto it = start; it != end; ++it, ++m_checked) {
11705
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 const std::string filename = it->second;
11706 110309 auto &files = m_dirs[it->first];
11707
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 const std::string phy_filename = files.path() + filename;
11708
11709 space_id_t space_id;
11710
11711
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 space_id = Fil_system::get_tablespace_id(phy_filename);
11712
11713
2/4
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110309 times.
✗ Branch 3 not taken.
110309 if (space_id != 0 && space_id != dict_sys_t::s_invalid_space_id) {
11714
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 std::lock_guard<std::mutex> guard(*mutex);
11715
11716
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 auto ret = unique->insert(space_id);
11717
11718 size_t n_files;
11719
11720
1/2
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
110309 n_files = files.add(space_id, filename);
11721
11722
3/4
✓ Branch 0 taken 110308 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 110308 times.
110309 if (n_files > 1 || !ret.second) {
11723
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 duplicates->insert(space_id);
11724 }
11725
11726
0/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
110309 } else if (space_id != 0 &&
11727 Fil_path::is_undo_tablespace_name(phy_filename)) {
11728 ib::info(ER_IB_MSG_373) << "Can't determine the undo file tablespace"
11729 << " ID for '" << phy_filename << "', could be"
11730 << " an undo truncate in progress";
11731
11732 } else {
11733 ib::info(ER_IB_MSG_374) << "Ignoring '" << phy_filename << "' invalid"
11734 << " tablespace ID in the header";
11735 }
11736
11737 110309 ++count;
11738
11739
3/6
✓ Branch 0 taken 110309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110309 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 110309 times.
110309 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
11740 ib::info(ER_IB_MSG_375) << "Thread# " << thread_id << " - Checked "
11741 << count << "/" << (end - start) << " files";
11742
11743 start_time = std::chrono::steady_clock::now();
11744
11745 printed_msg = true;
11746 }
11747 110309 }
11748
11749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23694 times.
23694 if (printed_msg) {
11750 ib::info(ER_IB_MSG_376) << "Checked " << count << " files";
11751 }
11752 23694 }
11753
11754 /** Print the duplicate filenames for a tablespce ID to the log
11755 @param[in] duplicates Duplicate tablespace IDs*/
11756 1 void Tablespace_dirs::print_duplicates(const Space_id_set &duplicates) {
11757 /* Print the duplicate names to the error log. */
11758
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (auto space_id : duplicates) {
11759 1 Dirs files;
11760
11761
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (auto &dir : m_dirs) {
11762
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 const auto names = dir.find_by_id(space_id);
11763
11764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (names == nullptr) {
11765 continue;
11766 }
11767
11768
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 files.insert(files.end(), names->begin(), names->end());
11769 }
11770
11771 /* Fixes the order in the mtr tests. */
11772
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::sort(files.begin(), files.end());
11773
11774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 ut_a(files.size() > 1);
11775
11776
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream oss;
11777
11778
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 oss << "Tablespace ID: " << space_id << " = [";
11779
11780
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (size_t i = 0; i < files.size(); ++i) {
11781
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 oss << "'" << files[i] << "'";
11782
11783
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (i < files.size() - 1) {
11784
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 oss << ", ";
11785 }
11786 }
11787
11788
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 oss << "]" << std::endl;
11789
11790
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 ib::error(ER_IB_MSG_377) << oss.str();
11791 1 }
11792 1 }
11793
11794 2143307 static bool fil_get_partition_file(const std::string &old_path [[maybe_unused]],
11795 ib_file_suffix extn [[maybe_unused]],
11796 std::string &new_path [[maybe_unused]]) {
11797 /* Safe check. Never needed on Windows. */
11798 #ifdef _WIN32
11799 return false;
11800 #else /* WIN32 */
11801
11802 #ifndef UNIV_HOTBACKUP
11803 /* Needed only for case sensitive file system. */
11804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2143307 times.
2143307 if (lower_case_file_system) {
11805 return false;
11806 }
11807
11808 /* Skip if not right file extension. */
11809
3/4
✓ Branch 0 taken 2143307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2055860 times.
✓ Branch 3 taken 87447 times.
2143307 if (!Fil_path::has_suffix(extn, old_path)) {
11810 2055860 return false;
11811 }
11812
11813 /* Check if partitioned table. */
11814
3/4
✓ Branch 0 taken 87447 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82036 times.
✓ Branch 3 taken 5411 times.
87447 if (!dict_name::is_partition(old_path)) {
11815 82036 return false;
11816 }
11817
11818 5411 std::string table_name;
11819 /* Get Innodb dictionary name from file path. */
11820
2/4
✓ Branch 0 taken 5411 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5411 times.
5411 if (!Fil_path::parse_file_path(old_path, extn, table_name)) {
11821 ut_d(ut_error);
11822 ut_o(return false);
11823 }
11824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5411 times.
5411 ut_ad(!table_name.empty());
11825
11826 /* Rebuild partition table name with lower case. */
11827
1/2
✓ Branch 0 taken 5411 times.
✗ Branch 1 not taken.
5411 std::string save_name(table_name);
11828
1/2
✓ Branch 0 taken 5411 times.
✗ Branch 1 not taken.
5411 dict_name::rebuild(table_name);
11829
11830
3/4
✓ Branch 0 taken 5411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4335 times.
✓ Branch 3 taken 1076 times.
5411 if (save_name.compare(table_name) == 0) {
11831 4335 return false;
11832 }
11833
11834 /* Build new partition file name. */
11835
1/2
✓ Branch 0 taken 1076 times.
✗ Branch 1 not taken.
1076 new_path = Fil_path::make_new_path(old_path, table_name, extn);
11836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1076 times.
1076 ut_ad(!new_path.empty());
11837 #endif /* !UNIV_HOTBACKUP */
11838
11839 1076 return true;
11840 #endif /* WIN32 */
11841 5411 }
11842
11843 #ifndef UNIV_HOTBACKUP
11844 607 static void fil_rename_partition_file(const std::string &old_path,
11845 ib_file_suffix extn, bool revert,
11846 bool import) {
11847 607 std::string new_path;
11848
11849
2/4
✓ Branch 0 taken 607 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 607 times.
607 if (!fil_get_partition_file(old_path, extn, new_path)) {
11850 ut_d(ut_error);
11851 ut_o(return );
11852 }
11853
11854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 607 times.
607 ut_ad(!new_path.empty());
11855
11856
1/2
✓ Branch 0 taken 607 times.
✗ Branch 1 not taken.
607 bool old_exists = os_file_exists(old_path.c_str());
11857
1/2
✓ Branch 0 taken 607 times.
✗ Branch 1 not taken.
607 bool new_exists = os_file_exists(new_path.c_str());
11858
11859 static bool print_upgrade = true;
11860 static bool print_downgrade = true;
11861 607 bool ret = false;
11862
11863
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 499 times.
607 if (revert) {
11864 /* Check if rename is required. */
11865
2/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
108 if (!new_exists || old_exists) {
11866 return;
11867 }
11868
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 ret = os_file_rename(innodb_data_file_key, new_path.c_str(),
11869 old_path.c_str());
11870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 ut_ad(ret);
11871
11872
3/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 99 times.
108 if (ret && print_downgrade) {
11873
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 ib::info(ER_IB_MSG_DOWNGRADE_PARTITION_FILE, new_path.c_str(),
11874 9 old_path.c_str());
11875 9 print_downgrade = false;
11876 }
11877 108 return;
11878 }
11879
11880 /* Check if rename is required. */
11881
2/4
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 499 times.
499 if (new_exists || !old_exists) {
11882 return;
11883 }
11884
11885 ret =
11886
1/2
✓ Branch 0 taken 499 times.
✗ Branch 1 not taken.
499 os_file_rename(innodb_data_file_key, old_path.c_str(), new_path.c_str());
11887
11888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 499 times.
499 if (!ret) {
11889 /* File rename failed. */
11890 ut_d(ut_error);
11891 ut_o(return );
11892 }
11893
11894
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 469 times.
499 if (import) {
11895
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 ib::info(ER_IB_MSG_UPGRADE_PARTITION_FILE_IMPORT, old_path.c_str(),
11896 30 new_path.c_str());
11897 30 return;
11898 }
11899
11900
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 428 times.
469 if (print_upgrade) {
11901
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 ib::info(ER_IB_MSG_UPGRADE_PARTITION_FILE, old_path.c_str(),
11902 41 new_path.c_str());
11903 41 print_upgrade = false;
11904 }
11905
2/2
✓ Branch 0 taken 469 times.
✓ Branch 1 taken 138 times.
607 }
11906 #endif /* !UNIV_HOTBACKUP */
11907
11908 24032 void Tablespace_dirs::set_scan_dir(const std::string &in_directory,
11909 bool is_undo_dir) {
11910
1/2
✓ Branch 0 taken 24032 times.
✗ Branch 1 not taken.
24032 std::string directory(in_directory);
11911
11912 24032 Fil_path::normalize(directory);
11913
11914
1/2
✓ Branch 0 taken 24032 times.
✗ Branch 1 not taken.
24032 add_path(directory, is_undo_dir);
11915 24032 }
11916
11917 95 void Tablespace_dirs::set_scan_dirs(const std::string &in_directories) {
11918
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 std::string directories(in_directories);
11919
11920 95 Fil_path::normalize(directories);
11921
11922 95 std::string separators;
11923
11924
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 separators.push_back(FIL_PATH_SEPARATOR);
11925
11926
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 add_paths(directories, separators);
11927 95 }
11928
11929 /** Discover tablespaces by reading the header from .ibd files.
11930 @return DB_SUCCESS if all goes well */
11931 11994 dberr_t Tablespace_dirs::scan() {
11932 11994 Scanned_files ibd_files;
11933 11994 Scanned_files undo_files;
11934 11994 uint16_t count = 0;
11935 11994 bool print_msg = false;
11936 11994 auto start_time = std::chrono::steady_clock::now();
11937
11938 /* Should be trivial to parallelize the scan and ID check. */
11939
2/2
✓ Branch 0 taken 12167 times.
✓ Branch 1 taken 11994 times.
24161 for (const auto &dir : m_dirs) {
11940
1/2
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
12167 const auto real_path_dir = dir.root().abs_path();
11941
11942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12167 times.
12167 ut_a(Fil_path::is_separator(dir.path().back()));
11943
11944
4/8
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12167 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12167 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12167 times.
✗ Branch 7 not taken.
12167 ib::info(ER_IB_MSG_379) << "Scanning '" << dir.path() << "'";
11945
11946 /* Walk the sub-tree of dir. */
11947
11948
1/2
✓ Branch 0 taken 12167 times.
✗ Branch 1 not taken.
12167 Dir_Walker::walk(real_path_dir, true, [&](const std::string &path) {
11949 /* If it is a file and the suffix matches ".ibd"
11950 or the undo file name format then store it for
11951 determining the space ID. */
11952
11953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2142700 times.
2142700 ut_a(path.length() > real_path_dir.length());
11954
2/4
✓ Branch 0 taken 2142700 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2142700 times.
2142700 ut_a(Fil_path::get_file_type(path) != OS_FILE_TYPE_DIR);
11955
11956 /* Check if need to alter partition file names to lower case. */
11957 2142700 std::string new_path;
11958
11959
3/4
✓ Branch 0 taken 2142700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 469 times.
✓ Branch 3 taken 2142231 times.
2142700 if (fil_get_partition_file(path, IBD, new_path)) {
11960 /* Note all old file names to be renamed. */
11961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 469 times.
469 ut_ad(!new_path.empty());
11962
1/2
✓ Branch 0 taken 469 times.
✗ Branch 1 not taken.
469 fil_system->add_old_file(path);
11963
11964 } else {
11965
1/2
✓ Branch 0 taken 2142231 times.
✗ Branch 1 not taken.
2142231 new_path.assign(path);
11966 }
11967
11968 /* Make the filename relative to the directory that was scanned. */
11969
1/2
✓ Branch 0 taken 2142700 times.
✗ Branch 1 not taken.
2142700 std::string file = new_path.substr(real_path_dir.length());
11970
11971
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2142698 times.
2142700 if (file.size() <= 4) {
11972 2 return;
11973 }
11974
11975 using Value = Scanned_files::value_type;
11976
11977
4/6
✓ Branch 0 taken 2142698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2142698 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 86840 times.
✓ Branch 5 taken 2055858 times.
2142698 if (Fil_path::has_suffix(IBD, file.c_str())) {
11978
2/4
✓ Branch 0 taken 86840 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 86840 times.
✗ Branch 3 not taken.
86840 ibd_files.push_back(Value{count, file});
11979
11980
3/4
✓ Branch 0 taken 2055858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23469 times.
✓ Branch 3 taken 2032389 times.
2055858 } else if (Fil_path::is_undo_tablespace_name(file)) {
11981
2/4
✓ Branch 0 taken 23469 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23469 times.
✗ Branch 3 not taken.
23469 undo_files.push_back(Value{count, file});
11982 }
11983
11984
3/6
✓ Branch 0 taken 2142698 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2142698 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2142698 times.
2142698 if (std::chrono::steady_clock::now() - start_time >= PRINT_INTERVAL) {
11985 ib::info(ER_IB_MSG_380)
11986 << "Files found so far: " << ibd_files.size() << " data files"
11987 << " and " << undo_files.size() << " undo files";
11988
11989 start_time = std::chrono::steady_clock::now();
11990 print_msg = true;
11991 }
11992
4/4
✓ Branch 0 taken 2142698 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2142698 times.
✓ Branch 3 taken 2 times.
2142702 });
11993
11994 12167 ++count;
11995 12167 }
11996
11997 /* Rename all old partition files. */
11998
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 fil_system->rename_partition_files(false);
11999
12000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11994 times.
11994 if (print_msg) {
12001 ib::info(ER_IB_MSG_381) << "Found " << ibd_files.size() << " '.ibd' and "
12002 << undo_files.size() << " undo files";
12003 }
12004
12005 11994 Space_id_set unique;
12006 11994 Space_id_set duplicates;
12007
12008 /* Get the number of additional threads needed to scan the files. */
12009
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 size_t n_threads = fil_get_scan_threads(ibd_files.size());
12010
12011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11994 times.
11994 if (n_threads > 0) {
12012 ib::info(ER_IB_MSG_382)
12013 << "Using " << (n_threads + 1) << " threads to"
12014 << " scan " << ibd_files.size() << " tablespace files";
12015 }
12016
12017 11994 std::mutex m;
12018
12019 using std::placeholders::_1;
12020 using std::placeholders::_2;
12021 using std::placeholders::_3;
12022 using std::placeholders::_4;
12023 using std::placeholders::_5;
12024 using std::placeholders::_6;
12025
12026 std::function<void(const Const_iter &, const Const_iter &, size_t,
12027 std::mutex *, Space_id_set *, Space_id_set *)>
12028
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 check = std::bind(&Tablespace_dirs::duplicate_check, this, _1, _2, _3, _4,
12029
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 _5, _6);
12030
12031
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 par_for(PFS_NOT_INSTRUMENTED, ibd_files, n_threads, check, &m, &unique,
12032 &duplicates);
12033
12034
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 duplicate_check(undo_files.begin(), undo_files.end(), n_threads, &m, &unique,
12035 &duplicates);
12036
12037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11994 times.
11994 ut_a(m_checked == ibd_files.size() + undo_files.size());
12038
12039
3/6
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11994 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11994 times.
✗ Branch 5 not taken.
35982 ib::info(ER_IB_MSG_383) << "Completed space ID check of " << m_checked.load()
12040
1/2
✓ Branch 0 taken 11994 times.
✗ Branch 1 not taken.
11994 << " files.";
12041
12042 dberr_t err;
12043
12044
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11993 times.
11994 if (!duplicates.empty()) {
12045
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 ib::error(ER_IB_MSG_384)
12046
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 << "Multiple files found for the same tablespace ID:";
12047
12048
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 print_duplicates(duplicates);
12049
12050 1 err = DB_FAIL;
12051 } else {
12052 11993 err = DB_SUCCESS;
12053 }
12054
12055 11994 return err;
12056 11994 }
12057
12058 24032 void fil_set_scan_dir(const std::string &directory, bool is_undo_dir) {
12059 24032 fil_system->set_scan_dir(directory, is_undo_dir);
12060 24032 }
12061
12062 95 void fil_set_scan_dirs(const std::string &directories) {
12063 95 fil_system->set_scan_dirs(directories);
12064 95 }
12065
12066 /** Discover tablespaces by reading the header from .ibd files.
12067 @return DB_SUCCESS if all goes well */
12068 11994 dberr_t fil_scan_for_tablespaces() { return fil_system->scan(); }
12069
12070 /** Check if a path is known to InnoDB meaning that it is in or under
12071 one of the four path settings scanned at startup for file discovery.
12072 @param[in] path Path to check
12073 @return true if path is known to InnoDB */
12074 16549 bool fil_path_is_known(const std::string &path) {
12075 16549 return fil_system->check_path(path);
12076 }
12077
12078 /** Get the list of directories that datafiles can reside in.
12079 @return the list of directories 'dir1;dir2;....;dirN' */
12080 11994 std::string fil_get_dirs() { return fil_system->get_dirs(); }
12081
12082 /** Free the data structures required for recovery. */
12083 11787 void fil_free_scanned_files() { fil_system->free_scanned_files(); }
12084
12085 /** Update the tablespace name. In case, the new name
12086 and old name are same, no update done.
12087 @param[in,out] space tablespace object on which name
12088 will be updated
12089 @param[in] name new name for tablespace */
12090 3060 void fil_space_update_name(fil_space_t *space, const char *name) {
12091
3/6
✓ Branch 0 taken 3060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3060 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3060 times.
✗ Branch 5 not taken.
3060 if (space == nullptr || name == nullptr || space->name == nullptr ||
12092
2/2
✓ Branch 0 taken 3055 times.
✓ Branch 1 taken 5 times.
3060 strcmp(space->name, name) == 0) {
12093 3055 return;
12094 }
12095
12096 5 dberr_t err = fil_rename_tablespace_by_id(space->id, space->name, name);
12097
12098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (err != DB_SUCCESS) {
12099 ib::warn(ER_IB_MSG_387) << "Tablespace rename '" << space->name << "' to"
12100 << " '" << name << "' failed!";
12101 }
12102 }
12103
12104 #ifndef UNIV_HOTBACKUP
12105 104555 bool Fil_path::is_valid_location(const char *space_name, space_id_t space_id,
12106 uint32_t fsp_flags, const std::string &path) {
12107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104555 times.
104555 ut_ad(!path.empty());
12108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104555 times.
104555 ut_ad(space_name != nullptr);
12109
12110 /* All files sent to this routine have been found by scanning known
12111 locations. */
12112
2/2
✓ Branch 0 taken 23325 times.
✓ Branch 1 taken 81230 times.
104555 ib_file_suffix type = (fsp_is_undo_tablespace(space_id) ? IBU : IBD);
12113
12114
2/2
✓ Branch 0 taken 81230 times.
✓ Branch 1 taken 23325 times.
104555 if (type == IBD) {
12115
1/2
✓ Branch 0 taken 81230 times.
✗ Branch 1 not taken.
81230 size_t dirname_len = dirname_length(path.c_str());
12116
1/2
✓ Branch 0 taken 81230 times.
✗ Branch 1 not taken.
81230 Fil_path dirpath(path.c_str(), dirname_len, true);
12117
12118 81230 bool is_shared = fsp_is_shared_tablespace(fsp_flags);
12119
1/2
✓ Branch 0 taken 81230 times.
✗ Branch 1 not taken.
81230 bool under_datadir = MySQL_datadir_path.is_ancestor(dirpath);
12120
12121
2/2
✓ Branch 0 taken 12021 times.
✓ Branch 1 taken 69209 times.
81230 if (is_shared) {
12122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12021 times.
12021 if (under_datadir) {
12123 ib::error(ER_IB_MSG_GENERAL_TABLESPACE_UNDER_DATADIR, path.c_str());
12124 return false;
12125 }
12126 } else {
12127 /* file-per-table */
12128 bool in_datadir =
12129
3/4
✓ Branch 0 taken 69086 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 123 times.
✗ Branch 3 not taken.
69209 (under_datadir ? false : MySQL_datadir_path.is_same_as(dirpath));
12130
12131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69209 times.
69209 if (in_datadir) {
12132 ib::error(ER_IB_MSG_IMPLICIT_TABLESPACE_IN_DATADIR, path.c_str());
12133 return false;
12134 }
12135
12136 /* Make sure that the last directory of an implicit tablespace is a
12137 filesystem charset version of the schema name. */
12138
3/4
✓ Branch 0 taken 69209 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 69011 times.
69209 if (!is_valid_location_within_db(space_name, path)) {
12139
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 ib::error(ER_IB_MSG_INVALID_LOCATION_WRONG_DB, path.c_str(),
12140 space_name);
12141 198 return false;
12142 }
12143 }
12144
2/2
✓ Branch 0 taken 81032 times.
✓ Branch 1 taken 198 times.
81230 }
12145
12146 104357 return true;
12147 }
12148
12149 69209 bool Fil_path::is_valid_location_within_db(const char *space_name,
12150 const std::string &path) {
12151 /* Strip off the basename to reduce the path to a directory. */
12152
1/2
✓ Branch 0 taken 69209 times.
✗ Branch 1 not taken.
69209 std::string dirpath{path};
12153 69209 auto pos = dirpath.find_last_of(SEPARATOR);
12154
1/2
✓ Branch 0 taken 69209 times.
✗ Branch 1 not taken.
69209 dirpath.resize(pos);
12155
12156 /* Only implicit tablespaces are sent to this routine.
12157 They are always prefixed by `schema/`. */
12158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69209 times.
69209 ut_ad(pos != std::string::npos);
12159
12160 /* Get the subdir that the file is in. */
12161 69209 pos = dirpath.find_last_of(SEPARATOR);
12162 std::string db_dir = (pos == std::string::npos)
12163 ? dirpath
12164
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 69209 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 69209 times.
✗ Branch 5 not taken.
69209 : dirpath.substr(pos + 1, dirpath.length());
12165
12166 /* Convert to lowercase if necessary. */
12167
2/4
✓ Branch 0 taken 69209 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 69209 times.
69209 if (innobase_get_lower_case_table_names() == 2) {
12168 Fil_path::convert_to_lower_case(db_dir);
12169 }
12170
12171 /* Make sure the db_dir matches the schema name.
12172 db_dir is in filesystem charset and space_name is usually in the
12173 system charset.
12174
12175 The problem here is that the system charset version of a schema or
12176 table name may contain a '/' and the tablespace name we were sent
12177 is a combination of the two with '/' as a delimiter.
12178 For example `my/schema` + `my/table` == `my/schema/my/table`
12179
12180 Search the space_name string backwards until we find the db name that
12181 matches the schema name from the path. */
12182
12183
1/2
✓ Branch 0 taken 69209 times.
✗ Branch 1 not taken.
69209 std::string name(space_name);
12184 69209 pos = name.find_last_of(SEPARATOR);
12185
1/2
✓ Branch 0 taken 69428 times.
✗ Branch 1 not taken.
69428 while (pos < std::string::npos) {
12186
1/2
✓ Branch 0 taken 69428 times.
✗ Branch 1 not taken.
69428 name.resize(pos);
12187
1/2
✓ Branch 0 taken 69428 times.
✗ Branch 1 not taken.
69428 std::string temp = name;
12188
2/2
✓ Branch 0 taken 69000 times.
✓ Branch 1 taken 428 times.
69428 if (temp == db_dir) {
12189 69000 return true;
12190 }
12191
12192 /* Convert to filename charset and compare again. */
12193
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 Fil_path::convert_to_filename_charset(temp);
12194
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 417 times.
428 if (temp == db_dir) {
12195 11 return true;
12196 }
12197
12198 /* Still no match, iterate through the next SEPARATOR. */
12199 417 pos = name.find_last_of(SEPARATOR);
12200
12201 /* If end of string is hit, there is no match. */
12202
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 219 times.
417 if (pos == std::string::npos) {
12203 198 return false;
12204 }
12205
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 69209 times.
69428 }
12206
12207 return true;
12208 69209 }
12209
12210 /** Convert filename to the file system charset format.
12211 @param[in,out] name Filename to convert */
12212 428 void Fil_path::convert_to_filename_charset(std::string &name) {
12213 428 uint errors = 0;
12214 char old_name[MAX_TABLE_NAME_LEN + 20];
12215 char filename[MAX_TABLE_NAME_LEN + 20];
12216
12217 428 strncpy(filename, name.c_str(), sizeof(filename) - 1);
12218 428 strncpy(old_name, filename, sizeof(old_name));
12219
12220
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 innobase_convert_to_filename_charset(filename, old_name, MAX_TABLE_NAME_LEN);
12221
12222
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 if (errors == 0) {
12223
1/2
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
428 name.assign(filename);
12224 }
12225 428 }
12226
12227 /** Convert to lower case using the file system charset.
12228 @param[in,out] path Filepath to convert */
12229 void Fil_path::convert_to_lower_case(std::string &path) {
12230 char lc_path[MAX_TABLE_NAME_LEN + 20];
12231
12232 ut_ad(path.length() < sizeof(lc_path) - 1);
12233
12234 strncpy(lc_path, path.c_str(), sizeof(lc_path) - 1);
12235
12236 innobase_casedn_path(lc_path);
12237
12238 path.assign(lc_path);
12239 }
12240
12241 1333115 void fil_purge() { fil_system->purge(); }
12242
12243 63301 size_t fil_count_undo_deleted(space_id_t undo_num) {
12244 63301 return fil_system->count_undo_deleted(undo_num);
12245 }
12246
12247 #endif /* !UNIV_HOTBACKUP */
12248
12249 #define PAGE_TYPE(x) \
12250 case x: \
12251 return #x;
12252
12253 12423 const char *fil_get_page_type_str(page_type_t type) noexcept {
12254
12/33
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 241 times.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11458 times.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 141 times.
✓ Branch 9 taken 17 times.
✓ Branch 10 taken 64 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 27 times.
✓ Branch 18 taken 16 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
12423 switch (type) {
12255 387 PAGE_TYPE(FIL_PAGE_INDEX);
12256 PAGE_TYPE(FIL_PAGE_RTREE);
12257 6 PAGE_TYPE(FIL_PAGE_SDI);
12258 241 PAGE_TYPE(FIL_PAGE_UNDO_LOG);
12259 26 PAGE_TYPE(FIL_PAGE_INODE);
12260 PAGE_TYPE(FIL_PAGE_IBUF_FREE_LIST);
12261 11458 PAGE_TYPE(FIL_PAGE_TYPE_ALLOCATED);
12262 30 PAGE_TYPE(FIL_PAGE_IBUF_BITMAP);
12263 141 PAGE_TYPE(FIL_PAGE_TYPE_SYS);
12264 17 PAGE_TYPE(FIL_PAGE_TYPE_TRX_SYS);
12265 64 PAGE_TYPE(FIL_PAGE_TYPE_FSP_HDR);
12266 PAGE_TYPE(FIL_PAGE_TYPE_XDES);
12267 PAGE_TYPE(FIL_PAGE_TYPE_BLOB);
12268 PAGE_TYPE(FIL_PAGE_TYPE_ZBLOB);
12269 PAGE_TYPE(FIL_PAGE_TYPE_ZBLOB2);
12270 PAGE_TYPE(FIL_PAGE_TYPE_UNKNOWN);
12271 PAGE_TYPE(FIL_PAGE_COMPRESSED);
12272 27 PAGE_TYPE(FIL_PAGE_ENCRYPTED);
12273 16 PAGE_TYPE(FIL_PAGE_COMPRESSED_AND_ENCRYPTED);
12274 PAGE_TYPE(FIL_PAGE_ENCRYPTED_RTREE);
12275 PAGE_TYPE(FIL_PAGE_SDI_BLOB);
12276 PAGE_TYPE(FIL_PAGE_SDI_ZBLOB);
12277 PAGE_TYPE(FIL_PAGE_TYPE_LOB_INDEX);
12278 PAGE_TYPE(FIL_PAGE_TYPE_LOB_DATA);
12279 10 PAGE_TYPE(FIL_PAGE_TYPE_LOB_FIRST);
12280 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FIRST);
12281 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_DATA);
12282 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_INDEX);
12283 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FRAG);
12284 PAGE_TYPE(FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY);
12285 PAGE_TYPE(FIL_PAGE_TYPE_RSEG_ARRAY);
12286 PAGE_TYPE(FIL_PAGE_TYPE_LEGACY_DBLWR);
12287 }
12288 ut_d(ut_error);
12289 ut_o(return "UNKNOWN");
12290 }
12291
12292 8 bool fil_is_page_type_valid(page_type_t type) noexcept {
12293
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (fil_page_type_is_index(type)) {
12294 2 return true;
12295 }
12296
12297
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (type <= FIL_PAGE_TYPE_LAST && type != FIL_PAGE_TYPE_UNUSED) {
12298 6 return true;
12299 }
12300
12301 ut_d(ut_error);
12302 ut_o(return false);
12303 }
12304
12305 std::ostream &Fil_page_header::print(std::ostream &out) const noexcept {
12306 /* Print the header information in the order it is stored. */
12307 out << "[Fil_page_header: FIL_PAGE_OFFSET=" << get_page_no()
12308 << ", FIL_PAGE_TYPE=" << get_page_type()
12309 << ", FIL_PAGE_SPACE_ID=" << get_space_id() << "]";
12310 return out;
12311 }
12312
12313 27862 space_id_t Fil_page_header::get_space_id() const noexcept {
12314 27862 return mach_read_from_4(m_frame + FIL_PAGE_SPACE_ID);
12315 }
12316
12317 27862 page_no_t Fil_page_header::get_page_no() const noexcept {
12318 27862 return mach_read_from_4(m_frame + FIL_PAGE_OFFSET);
12319 }
12320
12321 uint16_t Fil_page_header::get_page_type() const noexcept {
12322 return mach_read_from_2(m_frame + FIL_PAGE_TYPE);
12323 }
12324
12325 78656509 fil_node_t *fil_space_t::get_file_node(page_no_t *page_no) noexcept {
12326
2/2
✓ Branch 0 taken 20165 times.
✓ Branch 1 taken 78636521 times.
78656509 if (files.size() > 1) {
12327
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 20165 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20165 times.
20165 ut_a(id == TRX_SYS_SPACE || purpose == FIL_TYPE_TEMPORARY);
12328
12329
1/2
✓ Branch 0 taken 32219 times.
✗ Branch 1 not taken.
32219 for (auto &f : files) {
12330
2/2
✓ Branch 0 taken 20165 times.
✓ Branch 1 taken 12054 times.
32219 if (f.size > *page_no) {
12331 20165 return &f;
12332 }
12333 12054 *page_no -= f.size;
12334 }
12335
12336
2/2
✓ Branch 0 taken 78636409 times.
✓ Branch 1 taken 17 times.
78636521 } else if (!files.empty()) {
12337 78636409 fil_node_t &f = files.front();
12338
12339
8/8
✓ Branch 0 taken 18705477 times.
✓ Branch 1 taken 59931126 times.
✓ Branch 2 taken 18704315 times.
✓ Branch 3 taken 1162 times.
✓ Branch 4 taken 78635200 times.
✓ Branch 5 taken 241 times.
✓ Branch 6 taken 78636379 times.
✓ Branch 7 taken 224 times.
78636441 if ((fsp_is_ibd_tablespace(id) && f.size == 0) || f.size > *page_no) {
12340 /* We do not know the size of a single-table tablespace
12341 before we open the file */
12342 78636379 return &f;
12343 }
12344 /* The page is outside the current bounds of the file. We should not assert
12345 here as we could be loading pages in buffer pool from dump file having pages
12346 from dropped tablespaces. Specifically, for undo tablespace it is possible
12347 to re-use the dropped space ID and the page could be out of bound. We need
12348 to ignore such cases. */
12349 }
12350
12351 241 return nullptr;
12352 }
12353
12354 100124955 bool fil_space_t::is_deleted() const {
12355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100125224 times.
100124955 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12356 100125224 return m_deleted;
12357 }
12358
12359 1341417240 bool fil_space_t::was_not_deleted() const {
12360 /* This is not a critical assertion - if you have this mutex, then possibly
12361 you want to call !is_deleted(). */
12362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1225646207 times.
1341417240 ut_ad(!fil_system->shard_by_id(id)->mutex_owned());
12363 1225646207 return !m_deleted;
12364 }
12365
12366 #ifndef UNIV_HOTBACKUP
12367 42387011 uint32_t fil_space_t::get_current_version() const {
12368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42387193 times.
42387011 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12369 42387193 return m_version;
12370 }
12371 3306898187 uint32_t fil_space_t::get_recent_version() const {
12372 /* This is not a critical assertion - if you have this mutex, then possibly
12373 you want to call get_current_version(). */
12374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3306948342 times.
3306898187 ut_ad(!fil_system->shard_by_id(id)->mutex_owned());
12375 3306948342 return m_version;
12376 }
12377 1336305 bool fil_space_t::has_no_references() const {
12378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1336305 times.
1336305 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12379 2672610 return m_n_ref_count.load() == 0;
12380 }
12381 2954 size_t fil_space_t::get_reference_count() const {
12382 /* This should be only called on server shutdown. */
12383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2954 times.
2954 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12384 5908 return m_n_ref_count.load();
12385 }
12386
12387 #endif /* !UNIV_HOTBACKUP */
12388
12389 197546 void fil_space_t::set_deleted() {
12390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197546 times.
197546 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197546 times.
197546 ut_a(files.size() == 1);
12392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197546 times.
197546 ut_a(n_pending_ops == 0);
12393
12394 #ifndef UNIV_HOTBACKUP
12395 197546 bump_version();
12396
12397 197546 m_deleted = true;
12398 #endif /* !UNIV_HOTBACKUP */
12399 197546 }
12400
12401 #ifndef UNIV_HOTBACKUP
12402
12403 285587 void fil_space_t::bump_version() {
12404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285587 times.
285587 ut_ad(fil_system->shard_by_id(id)->mutex_owned());
12405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285587 times.
285587 ut_a(files.size() == 1);
12406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285587 times.
285587 ut_a(n_pending_ops == 0);
12407
12408 /* Bump the version. This will make all pages in buffer pool that reference
12409 the current space version to be stale and freed on first encounter. */
12410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285587 times.
285587 ut_a(stop_new_ops);
12411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285587 times.
285587 ut_a(!m_deleted);
12412
12413 285587 ++m_version;
12414 285587 }
12415
12416 /** Mark space as corrupt
12417 @param space_id space id */
12418 void fil_space_set_corrupt(space_id_t space_id) {
12419 auto *const shard = fil_system->shard_by_id(space_id);
12420
12421 shard->mutex_acquire();
12422
12423 auto *const space = shard->get_space_by_id(space_id);
12424
12425 if (space) space->is_corrupt = true;
12426
12427 shard->mutex_release();
12428 }
12429
12430 11869 void fil_system_acquire() {
12431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11869 times.
11869 ut_ad(fil_system);
12432 11869 fil_system->mutex_acquire_all();
12433 11869 }
12434
12435 11869 void fil_system_release() {
12436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11869 times.
11869 ut_ad(fil_system);
12437 11869 fil_system->mutex_release_all();
12438 11869 }
12439
12440 22 void fil_lock_shard_by_id(space_id_t space_id) {
12441 22 auto *const shard = fil_system->shard_by_id(space_id);
12442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 ut_ad(shard);
12443 22 shard->mutex_acquire();
12444 22 }
12445
12446 22 void fil_unlock_shard_by_id(space_id_t space_id) {
12447 22 auto *const shard = fil_system->shard_by_id(space_id);
12448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 ut_ad(shard);
12449 22 shard->mutex_release();
12450 22 }
12451
12452 #endif /* !UNIV_HOTBACKUP */
12453